Ruby Essential Training

Ruby Essential Training

with Kevin Skoglund

 


In Ruby Essential Training, expert instructor Kevin Skoglund teaches the fundamentals of Ruby, the popular object-oriented open-source programming language. Kevin begins by walking through the basic data types, demonstrating Ruby's control structures (loops, iterators, conditionals, and code blocks) and showcasing the elegant syntax structure of the language. Kevin explains variable scope and shows how to use methods, arguments, and return values to write efficient code. After covering the fundamentals, Kevin focuses on Ruby's object-oriented features. He shows how to define classes and explores OOP concepts, including instances, attributes, access control, and inheritance. Exercise files accompany the course.
Topics include:
  • Using Ruby in the Interactive Ruby Shell and in standalone scripts
  • Learning to write custom code blocks to find, merge, and sort
  • Using modules for namespacing or as mix-ins
  • Reading from and writing to files
  • Creating a full Ruby project from start to finish

show more

author
Kevin Skoglund
subject
Developer, Web, Programming Languages, Web Development
software
Ruby
level
Beginner
duration
6h 54m
released
Oct 14, 2009

Share this course

Ready to join? subscribe


Keep up with news, tips, and latest courses.

submit Course details submit clicked more info

Please wait...

Search the closed captioning text for this course by entering the keyword you’d like to search, or browse the closed captioning text by selecting the chapter name below and choosing the video title you’d like to review.



Introduction
Welcome
00:00(Music playing.)
00:03Welcome to Ruby Essential Training.
00:05My name is Kevin Skoglund.
00:07I run a web development company called Nova Fabrica, where we develop websites
00:10and web applications.
00:12In this course, we are going to learn to program using Ruby, the popular
00:15object-oriented programming language.
00:18To begin with, we will examine the basic object types in Ruby, as well as the
00:21fundamentals of the language syntax.
00:23We will learn how object-oriented programming works and I'll walk you through
00:26the steps to enable you to read and to write to files from your code.
00:30Finally, we'll get practical hands- on experience using Ruby by building a
00:34restaurant guide for managing your favorite restaurants.
00:37Now, it doesn't matter if you're a beginner or if you have prior
00:39experience. We'll cover all the fundamentals you need and many more advanced concepts as well.
00:44If you're interested in website development, you will end with a solid
00:47foundation in Ruby that will make learning Ruby on Rails much easier.
00:50Let's get started learning how to program with Ruby.
Collapse this transcript
Using the exercise files
00:00If you are a Premium member of the Lynda.com Training Library, or if you're
00:04watching this tutorial on a disc, then you will have access to the exercise
00:07files that accompany this title.
00:09The exercise files are arranged by chapter and by movie.
00:13You can find the exercise files that corresponded to the movie you're watching
00:15by first looking for the chapter number and then the movie number.
00:18Now, of course to use the exercise files, you want to make sure that you have
00:21Ruby installed first, and Cchapter 1 can help you with that.
00:24Once you're confident you have everything installed, then you will want to copy
00:27the folder of Exercise Files to a convenient location, like your Desktop.
00:31It's a good idea to do it as a copy, so that you still have the original files
00:34to refer back to once you make changes.
00:36On my Mac, I will Option+Drag the folder to the Desktop in order make a copy.
00:41Once it's copied, then we can just remove the chapter number and movie number
00:44from the front of the file name, and now your files will be the same as mine,
00:48and you'll be able to work right along with me.
00:49Don't forget you can also use the exercise files to check your work as you go along.
00:53We've done something a little bit different for Chapters 2, 3, and 4.
00:57Instead of having a folder full of files, there's just a single Ruby file, which
01:01is actually a transcript of what I type during the movie.
01:05So this is there as a convenience for you to refer to.
01:07You can actually run it as a Ruby file and get the same results, or you can just
01:11refer to it, as I'm typing the same thing during the course of the movie.
01:15If you're a monthly or annual subscriber to Lynda.com, you won't have the
01:18exercise files that accompany this tutorial, but you can follow right along with me.
01:22Everything that's in the exercise files we will create during the tutorials.
01:26So as long as you continue to work along with me, your files will exactly mirror
01:30what's in the exercise files.
01:31Remember that you can pause the video or rewind if you need some more time to copy something down.
Collapse this transcript
1. Getting Started with Ruby
Introducing Ruby
00:00I'd like to start out our Ruby Essential Training by introducing Ruby to you,
00:03and first answering the question, what is Ruby?
00:06You probably already know that Ruby is a programming language.
00:08Its a language that was created in Japan, in 1995, by Yukihiro Matsumoto.
00:13People just call him Matz for short.
00:15Ruby has a syntax or a language structure that's a lot like Perl, Python, and Smalltalk.
00:20In fact, Matsumoto said that when he created Ruby, he was trying to create a
00:23language that was more powerful than Perl, and more object-oriented than Python.
00:27Now, if you don't know any of those other three languages, that's not a problem.
00:31I'm going to teach you everything about Ruby that you need to know.
00:33But if you do already know them, you'll have a little bit of a head start and
00:36you'll recognize a lot of the things in Ruby as we go through them.
00:39Now, Ruby is not a compiled language.
00:42Some other compiled languages would be C++, Java, or Visual Basic.
00:46A compiled language is a language where you write the code and then you have to
00:49run it through another computer program or compiler in order to come out with an
00:53application that you can actually run at the end.
00:55Well instead, Ruby is going to be an interpreted language.
00:58So we're going to write our code and then it will just get interpreted straight
01:02from the code when we're ready to run it.
01:04So we're not going to have to go through this extra step of compiling it into
01:08something that will run. Our code will run on its own.
01:10But we're going to need to have a Ruby interpreter to do that.
01:14So in the Installation section we will be installing the Ruby interpreter that
01:18will let us do that.
01:18Now, you may be coming to this training because you've heard positive things
01:21about Ruby, but you may not really be sure why Ruby, why not one of these other languages?
01:26Well, first and foremost, Ruby is fully object-oriented, and if you're not
01:30familiar with object-oriented, we'll talk about it a lot more later on and
01:33you'll see why it's such a good thing.
01:34If you're are familiar with it from other languages, you'll find that Ruby is
01:38very object-oriented. Almost everything in Ruby is an object.
01:41That's a really nice way to work, once you're used to working with objects.
01:44Ruby also has easily readable code.
01:46It reads a lot like English.
01:48So we don't spend a lot of time trying to decipher the code that's on the
01:51screen to understand what our program is doing.
01:54When we're writing our code, it also has an unsurprising syntax, naming,
01:58and behavior to it.
02:00So things often just work the way you'd expect them to work.
02:03If you say you want to sort, then it sorts it.
02:05If you want to find, it finds.
02:07Reverse, reverses, and so on.
02:09Another nice feature that's common to a lot of languages now is that it's
02:12whitespace independent.
02:14So having extra tabs or extra spaces doesn't really make a difference.
02:18And unlike a lot of languages, there are no semicolons.
02:21If you've worked with semicolons in another language, like PHP, for example,
02:24you're going to love the fact that you don't have to worry about that trailing
02:28semicolon at the end. Ruby can sort it out for you.
02:31Last of all, Ruby has lots of what we call syntactic sugar.
02:35That means that the syntax of the language is such that it helps you out.
02:39It does nice things for you, or allows you to write things in a simpler way so
02:43that we can have sort of a shortcut for ourselves. That's the sugar.
02:46The opposite of syntactic sugar is syntactic vinegar.
02:49So it's a pleasant way of working with the syntax.
02:51And there are lots of nice bits of syntactic sugar in Ruby and we'll see those
02:54as we learn the basics.
02:55I also just want to take a second to clear up a common misconception and that
02:59is the difference between Ruby and Ruby on Rails.
03:02Ruby on Rails has gotten a lot of publicity, because a lot of people are using
03:05it for their web development.
03:07I use it and I love it.
03:08But what we're talking about here is Ruby, and that's different from Ruby on Rails.
03:11Ruby on Rails is a web framework that's been written in Ruby.
03:16So it uses Ruby to build a web framework.
03:18So when we're talking about Ruby on Rails, we're talking about the web framework
03:22that helps you build websites.
03:23When we talk about Ruby though, we're just talking about the language and
03:27it's a multipurpose language.
03:28It's not just for the web.
03:30In fact, in our exercises in this tutorial we're going to create a standalone,
03:34non-Internet application, that won't use the web at all.
03:37So you'll be able to see how Ruby can be used outside of the web context.
03:41Now that we've taken a look at what Ruby is, we're ready to make sure that we
03:44have that Ruby interpreter installed on our computers.
Collapse this transcript
Installing Ruby on a Mac
00:00In this movie, I am going to help Mac users get everything installed that they
00:03need to be able to program in the Ruby language.
00:05I am going to start by first giving an overview and then I'll walk you
00:08through it step-by-step.
00:09The first thing I want to do is point you to the primary resource for the Ruby
00:12language and that's the Ruby language website, ruby-lang.org.
00:17So if you go to that website, it will always have the latest information about
00:20the current version of Ruby and even some installation instructions and some
00:24links to download it.
00:25So if the things that I tell you about installation change in the future,
00:29let's say a new operating system version comes out or suddenly some kind of bug comes up,
00:33so that it's not working anymore, your first resource that you want to go to
00:36is that ruby-lang site and see if you can find the problem there, because
00:40they'll probably let you know, "look, this is what you need to do if you're using
00:43this operating system" and so on.
00:45We'll take a look at that in a moment.
00:46The first of the pieces that we know we're going to need to be able to program
00:49in the Ruby language is the Ruby interpreter.
00:52It's going to interpret Ruby for us.
00:54If you're using Mac OS X, you probably already have a version of
00:56Ruby pre-installed.
00:57Now this may not be the correct version and you may need to update it. Let's take a look.
01:01So if you have 10.1, you may have problems running Ruby.
01:05Some people have had success, some people have had trouble. Hopefully,
01:07that's an operating system that's now seven or eight- years-old and you've upgraded to something else.
01:1210.2 and 10.3, you'll want to either install or upgrade Ruby by following the
01:16instructions on that Ruby language site.
01:19And if you're on 10.4, which is Tiger, or 10.5, Leopard, which is where I am
01:23guessing most of you are, you'll have a version of Ruby that's going to work
01:27perfectly fine for the purposes of our tutorial.
01:30You could go ahead and upgrade to a newer version.
01:33In fact, there is a newer version than 1.8.6 out and there may be other ones
01:36after this training is published, they come out.
01:38You can go ahead and use those newer ones if you want, but you'll want to make
01:41sure that you have something at least 1.8.2 before proceeding and that's what
01:45ships with those and no installation will be needed.
01:48So you'll be all set to go. That makes it nice and easy for you.
01:51The other two pieces that we're going to need are the text editor and the command line.
01:54The text editor is going to let us write files in Ruby code.
01:58The command line is going to let us run those files and also interact with our
02:02Ruby interpreter in an interactive way. We'll see how to do that.
02:05Any text editor will really work.
02:07You don't want to use something like Microsoft Word or something; you want to
02:09use just a plain text editor that doesn't insert lots of formatting, or
02:13anything like that, just plain text, and the best ones are ones that are going
02:16to do code coloring for you.
02:18That is they're going to give color to the syntax on the page, so that you
02:21can quickly look at your code and tell what's what because things are of different colors.
02:25It's a nice feature that most text editors have.
02:28The text editor that I always recommend is TextMate.
02:31I think it's a fantastic one and I think you can't go wrong with it.
02:34macromates.com is the company that makes it.
02:36You can just go to their website.
02:38It's not that expensive to buy, but you also can download a free trial, if you
02:41want to try it out and it does code coloring and there is lots of other nice
02:45features that I think you'll really come to appreciate over time.
02:47So do yourself a favor and check that out.
02:50And for the command line, we'll be using Apple's program called Terminal
02:53and that is inside the Applications folder, inside Utilities, you'll find
02:56the program called Terminal. We can run that to directly interact on the
03:00command line with the Unix operating system that's running Mac OS X.
03:04So let's take a look now.
03:06Here I am on the Ruby Language website.
03:08You'll notice that there is a download link here and there is also one here.
03:11Those take me to the same place and that lets me download Ruby.
03:15You'll see that it gives me the Ruby Source Code if I want to download the full source.
03:19Ruby 1.9, it actually offers to give me in that format, or I can scroll on down
03:25past Windows and Linux, until I get to Ruby On OS X and it basically tells you
03:29the same information that I just told you, and gives you some more helpful links
03:33if you want to upgrade and I wanted to point out down here, probably the best
03:37things of all for Tiger and Leopard, these articles down here will take you to
03:42the steps of installing Ruby and also Rails.
03:45Now we only want to follow the first couple of steps to get Ruby installed.
03:48It goes on and installs MySQL and Rails and everything else.
03:51We're just going to want to focus on Ruby but those can all be helpful for you,
03:54if you decide that you want to upgrade.
03:56Now let's take a look at our command line.
03:57If I go to Applications to my Applications folder, if I go into Utilities, inside
04:04my Utilities, if I scroll down, you'll see I have Terminal and this will open
04:08up our command line that will allow us to interact directly with the Unix operating system.
04:11Now I want to start out by just saying ruby and then dash v and that should work for you.
04:17If you have Ruby installed, it should come up and tell you which version,
04:21just by typing ruby -v.
04:22If you didn't get that, then you don't have Ruby installed or else there is
04:26something that's gone wrong and you'll need to troubleshoot it.
04:29But on Tiger and Leopard, you should get back either Ruby 1.8.2 or something
04:34later than that by just issuing that command.
04:36We can also type in which ruby and it will actually tells us where it's located
04:41and that's also useful to know.
04:42It's inside usr/bin and that's where the program has actually been put.
04:46It's inside that folder.
04:47So that's the version of Ruby that we are running and that's where it's located.
04:50So we know that we have Ruby. We know that we now have a command line.
04:53The last thing is just go to that MacroMates website that I told you about,
04:57macromates.com.
04:59Here it is for TextMate.
05:00You'll see we have a free 30-day trial.
05:02You can just download.
05:03It's a simple installer; you can go ahead and do that for yourself.
05:06I've already installed it and once I downloaded it and installed it, then I just
05:10simply drag a copy of it to my dock here, so that I have it nice and accessible.
05:14I have also got Terminal that I've just dragged to my dock so that that's
05:16accessible as well, and I can just switch between those to bring them up.
05:20That's all we need to be able to use Ruby. It's that easy.
05:23Luckily, all this is a pre-installed with the Mac, so there is really just not that much to do.
05:27Now, we are ready to start using Ruby.
Collapse this transcript
Installing Ruby on Windows
00:00In this movie I am going to help Windows users get everything installed that
00:03they are going to need to be able to program in the Ruby Language.
00:06Let me start by first giving you an overview of the installation and then
00:09I will walk you through it step by step.
00:10The first thing I want to show you is the main resource for the Ruby Language,
00:13and that's the Ruby Language website, and that's www.ruby-lang.org.
00:19You can always go to this website in order to get the latest information about
00:22Ruby and to get help with installing.
00:24So if any of the installation instructions that I give you coming up in this
00:27movie fall out of date, let's say a newer operating system comes out or some
00:31kind of incompatibility with a future version of Ruby comes up, this is the
00:35first place you will want to go to troubleshoot it, because they will help you
00:37figure out what version you ought to be installing with what operating system.
00:39Now let's walk through what we need for installation.
00:42There are going to be three pieces.
00:44The first is the Ruby interpreter.
00:46Remember we talked about that Ruby is an interpreted language, so we will need
00:48to install that interpreter.
00:49It doesn't come with Windows by default.
00:52The easiest way to do that is going to be a one-click installer that's on
00:55that ruby-lang site.
00:56At the moment if we use that one-click installer, it's going to install Ruby
00:59version v1.8.6 for us.
01:01Now, there are newer versions of Ruby that are already available.
01:04In fact, we are all the way up to 1.9 now.
01:06And that one-click installer may be updated in the future to have a different version.
01:10Don't worry about which version it is.
01:11Any version is going to work for the things that we are going to do in this tutorial.
01:14So go ahead and install whatever version is in that one-click installer and you
01:18should be good to go.
01:19The second thing we will want to make sure we have available to us is a text editor.
01:23Any plain text editor will work for us.
01:25What you won't want to do is use something like a word processing program, like
01:28Microsoft Word, that includes a lot of formatting information in addition to the text.
01:33We want just the text, so that the formatting information doesn't get in the way.
01:36Now, the best text editors are going to be ones that offer us code coloring.
01:40That is that they are going to give our syntax, our Ruby Language, different
01:44colors to different parts of the language.
01:46So that makes it nice and easy for us to see what's happening on the page,
01:49because things are broken up by color.
01:51There are lot of text editors out there.
01:52I am just going to mention two.
01:53The first is SciTE, which comes with the Ruby installer.
01:56So when we use that one-click installer, we will also get SciTE and we could use that.
02:00A third party one that I would recommend is E Text Editor.
02:03Its the sister program to the MacroMates' TextMate program, which is on the Mac.
02:08It works just the same way.
02:09It's a great text editor.
02:11It offers code coloring and everything.
02:13I believe it's not very expensive to purchase it, but they also have a trial period,
02:16if you want to just download it and try it.
02:18The third piece that we are going to need is going to be a command line interface.
02:21That's going to allow us to actually interact with Ruby and run our Ruby programs.
02:25That comes with Windows.
02:27It's inside the Accessories folder and it's called Command Prompt.
02:30So we already have that installed and I will show you where that's located.
02:33Now let me walk you through the steps.
02:35Here I am on the Ruby Language website, and you will see there is a link here
02:38for Downloads and there is another one over here that says Download Ruby.
02:41Those take me to the same page.
02:43So that will take me over here to the Installation page.
02:45You will see it says the current stable version at the moment is 1.9.1.
02:48Now, it may change by the time you watch this video, but don't worry about it.
02:52What we are interested in is going down here to the Ruby on Windows section, and
02:56the one-click installer.
02:58So whatever the one-click installer is here with the latest version is what you want to use.
03:011.8.6 is what it is at the moment.
03:04So we will click that.
03:05Windows of course will pop-up and say, what do you want to do with this?
03:08I will say let's run it.
03:09It will just take a moment while it downloads.
03:11Once your file is downloaded, if Microsoft Windows gives you a security warning,
03:15you will want to say Yes, it's okay to run this program.
03:17We will go ahead and allow the program to run.
03:20Now it's hidden, but it's down here in my bar, and there it is.
03:23The Wizard has popped up for installing Ruby 1.8.6. I will click Next.
03:27I will Agree to the terms of the License Agreements.
03:29You will see it's going to install SciTE at the same time.
03:32We also have RubyGems and European Keyboard that we can install.
03:35If you know that you are going to want to use Ruby on Rails at some point,
03:39you would want to go ahead and enable RubyGems as well.
03:42I am going to leave it off for now.
03:44Then it's going to install Ruby you can see.
03:45So I will hit Next.
03:47The Destination, go ahead and take whatever it gives you as a default and
03:52we will say Install.
03:55And then just sit back and wait while it installs.
03:57Once your installation is complete, you will want to click Next.
04:01And then click Finish.
04:02Now our installation is complete.
04:05We can close up Internet Explorer and then we can go to All Programs from the
04:10Start menu and what we want to look for here is Accessories and inside
04:14Accessories you will find Command Prompt.
04:17You could also do a search for Command Prompt and this will then take you
04:20to the Command Prompt.
04:21So now we know where that's located.
04:22We know how to find that.
04:24We should be able to just type ruby-v, and it comes up and tells us, yes,
04:28you have Ruby installed and it's version 1.8.6.
04:32If we had tried that before the installation, ruby-v, it would have just told us
04:36that, sorry, I don't understand that command.
04:38I don't have Ruby installed.
04:40You remember that the last piece we need is going to be the text editor.
04:42So you can download E Text Editor.
04:44That's what I have already done here, or I just want to show you where
04:47that SciTE program is.
04:48If you go to All Programs and then inside the Ruby folder, where it installed
04:52everything, you will find SciTE right here, SciTE.
04:56So click on that and now we are inside that SciTE text editor, so that you can
05:00go ahead and start typing here, for example.
05:02We will talk about what to type and how to get that going.
05:05But that's where that application is loaded, if it installed with it.
05:08So you have a text editor, but you can also download another one or use
05:12something else if you are more comfortable with it.
05:13That's all there is to getting things installed with Windows.
05:16Now we are ready to start using Ruby.
Collapse this transcript
Using Ruby
00:00Now that we have everything we need for programming in Ruby installed on our
00:03computers, we are ready to take a look at how to use Ruby.
00:06There are three different ways that I want us to look at.
00:09The first is going to be a single command.
00:11The second will be using a Ruby file, actually saving a file that has Ruby code in it.
00:16The third will be IRB, the Interactive Ruby Shell.
00:20Now, we are going to look at the first two in this movie and we will spend some
00:22more time with IRB in the next movie.
00:25All three of these ways of interacting with Ruby are going to require that we
00:28use our command line.
00:29So here I am inside my command line program on the Mac, which is Terminal.
00:32If you are on a PC, you will want to use the Command Prompt application that we
00:36talked about in the Installation section.
00:38But once you come up in there, you should be able to type Ruby and then -v,
00:41and it will let you know that you have Ruby installed and report what version you have.
00:45Again, don't worry if your version is not the same as mine. We talked about in
00:48the Installation section that most versions are going to work just fine, as long
00:51as we have Ruby installed.
00:53Running a single command is as easy as typing Ruby and then -e, to let it know
00:58they we are going to use a single command version of Ruby, -e.
01:02And then a single quote and our Ruby command, puts 123, and another single quote.
01:08That's the command that we want to execute, the single line of Ruby.
01:12So now we have learned our first Ruby command, puts, and that's actually 123,
01:17not 1, 2, 3, even though I said it 1, 2, 3.
01:19We will hit Return, and you will see what it does. puts actually output 123.
01:25It put it to whatever our standard out was, which in this case was just
01:29the Terminal window.
01:30Before we move on, let's go ahead and take a look at our second Ruby command,
01:33which is going to be print.
01:36It does something very similar to puts.
01:38Now, notice the difference. Notice where print went. print is right before my
01:42command prompt. The difference is that there is no line return after print.
01:46So puts outputs whatever you asked it to and adds a line return at the end.
01:51print just outputs whatever you have asked it to do, and does not put that line return.
01:55So now we know two bits of Ruby, puts and print.
01:57Let's take a look at how to do this with the file.
02:00In order to do that, we will need our text editor.
02:01I am going to open up TextMate, which is mine, and I am just going to put a
02:04simple Ruby command in here, puts 123, and then right after it let's put print
02:09456 and then puts 789.
02:12So we are going to Save this and we are going to call this file simple_file, and
02:18the ending is going to be .rb, to let it know that it's a Ruby file that ought
02:22to be run with Ruby. .rb is going to be the extension.
02:24We are always going to want to use that.
02:27You can save it anywhere you like.
02:28This is not like a web application where we need to put these in a certain sites
02:31directory or something like that.
02:32These can be run absolutely anywhere on your computer, but you want to put it
02:36someplace that's easy for you to find.
02:38I am going to go ahead and just put it on my Desktop.
02:40You can put it anywhere, in your Documents folder.
02:42It doesn't really matter, as long as you are able to find it from the command line.
02:45So I am going to save it there. So now it's saved.
02:48You see the code coloring took effect. That's the code coloring inside TextMate.
02:52Yours may be different, that's fine.
02:54If I come back over here to the command line now, I will need to navigate
02:57to where that file is.
02:59So we can see a list of the files that are in the current directory using ls, if
03:03we are on a Mac, or dir, if you are on a PC, and that will tell you what's
03:08inside that directory.
03:09We can change directories by using the cd command.
03:12So I am going to do cd into my Desktop folder.
03:15Hitting Tab allowed me to auto complete that name and then when I switch to the
03:19Desktop, now if I do an ls, you will see that I see that simple_file there.
03:23So once we are in the same directory as the file, then we can simply run Ruby,
03:29and then the filename, and once again the Tab lets me auto complete that name.
03:32So ruby simple_file, let's run it, and look what it output, 123, and then 456789.
03:39Now, notice if we go back, either we used puts here, print here, and puts here,
03:45and you will see the effect of not having that line return between the 6 and the 7.
03:48So that's all there is to being able to run a Ruby file.
03:51Now, if we hadn't navigated into Desktop, we could still do it just by providing
03:55the full path to the file.
03:57So if I go backwards a directory, we do that with the ..cd, and then dot dot
04:01goes back one, into the parent directory, and now I could just as easily say
04:05Ruby, and then Desktop/simple_file.rb, and that will also run that same file.
04:12So we just need to either be in the same folder, or we need to specify the full
04:15path on how we can get there.
04:17Before we move on, I just want to point out a couple of things about the file
04:19that we are working with here.
04:20First of all is that Ruby is whitespace independent.
04:24So it doesn't matter whether you put some extra whitespaces here, some extra
04:27ones here, it's still going to sort that out.
04:31So it's not going to really matter where those are.
04:32If we save this, come back here and we run the file again, you see we get the same results.
04:38The second thing I want to point out to you is the way we do comments.
04:42A comment in Ruby is simply the pound sign, also sometimes called the hash or the sharp.
04:47So we will put that in front of any of our comments.
04:49So then I will say print does not add a line return, and now we have a comment.
04:56Something that we can comment in our code and will not get executed.
04:59Notice also that we are not using any kind of semicolons or anything like that
05:02at the end of our lines.
05:03We just simply have a simple line return, and Ruby then knows, hey, we are ready
05:07to move on to something else.
05:09Print got everything that it needed on this line, so it's not waiting for
05:12more data to come in.
05:13So that must mean this is a new command, starting on the next line.
05:16So let's save it, and let's just run it to reassure ourselves that it all still works.
05:20Now, running a single command in Ruby isn't going to be useful for us that often.
05:24Running a file is going to be very useful for us, especially if we have lots and
05:28lots of code. We are not going to want to retype it every time. We will want to
05:31put it in a file, save it, and run it.
05:33But there is also Interactive Ruby Shell, which is going to be very useful for us,
05:38especially at the beginning, to try things out quickly.
05:41Once we actually start writing a program, we will put it in a file.
05:43For now, let's move over and look at IRB.
Collapse this transcript
Interactive Ruby Shell (IRB)
00:00Now that we have seen the first two ways that we can interact with Ruby,
00:02either using a single Ruby command, or creating a file with all of our Ruby code in it,
00:06now let's take a deeper look at the Interactive Ruby Shell, or more simply called IRB.
00:12IRB is going to be a command line interface to Ruby.
00:15Now, why that's really great is because it allows us to really interact with our code.
00:19We can see what's happening in real-time.
00:21It's a lot like a calculator.
00:23We can type in a couple of values, get a result, type in a few more values, get
00:27a different result, and then we can compare and see how things are working.
00:30It's a great place to test our code.
00:32So even when we are really advanced and we are writing all of our code in a very
00:36complex system of files that are all connected together, IRB is going to be a
00:41great way to quickly just pop open Ruby, try something out, test our theory, and
00:45then go back and actually add it to our code.
00:47So let's take a look.
00:49The way that we will access IRB is going to be from the command line.
00:52So when I say command line on a Mac, I am talking about the Terminal application
00:55that's inside your Utilities folder, and on a PC, that will be the Command
00:58Prompt application that's inside your Accessories folder.
01:01We saw how to find those earlier.
01:03To run it, we simply type irb at the command line.
01:06IRB is a program that's installed when we install Ruby.
01:09So we have irb, now I am inside, and you see I have a prompt there, letting me
01:13know that I am in IRB, it's waiting for a command.
01:16Now, IRB works a lot like a calculator. We can do 1+1.
01:21Comes back and tells us that it's 2.
01:23Or we can say 4+5, 9.
01:26Let's try something a little more complex, 3 * 50, or let's try 45/9.
01:34And last of all, let's just do some subtraction, 100-10.
01:36So you see that it just works like a calculator and just returns these values to us.
01:42Now, let's try the commands that we used earlier.
01:44We used puts, if you remember, 123.
01:47Now, this brings up an important point about IRB that I want you to pay
01:50close attention to.
01:51Notice that it returned two things to me.
01:54The first thing is 123, and then the arrow notation is next to nil.
01:59Just like we had the arrow notation up here, next to 90.
02:01So what's going on here?
02:03Puts is outputting it to IRB, just the same way that it outputted to our
02:08command line before, when we were running it from either the file or from a single line.
02:12This is the return value that comes back.
02:15So this is both the output that's happening and there is the return value and
02:19the return value of puts is always nil.
02:22The return value of these calculator operations that we were doing up here is
02:26the value that we are looking for.
02:28It's not actually outputting it; instead it's doing the calculation and
02:32giving us a return value.
02:34So this is an important difference.
02:35Let's try this, puts 1+1, and notice what it gives us.
02:39See, we get the 2 that's being put, and the return value is nil and that's
02:45distinctly different from just doing 1+1.
02:48So keep this in mind, because when we are doing a puts, which we will be doing a lot,
02:51we are going to be outputting something to the command line, so that we can see it,
02:55but the return value may be simply nil.
02:59Now, it's worth mentioning that nil means nothing. It's not 0.
03:02It's actually less than 0. It's nothing.
03:04It doesn't exist. It's no value at all.
03:07In a lot of languages this is just referred to as null.
03:09In Ruby it's going to be nil all the time.
03:13The next thing I want to point out to you about IRB is that you should be able
03:16to use your up arrows to get to old commands that you have issued before, and
03:19you can just hit return to execute them again, or the down arrow.
03:23Once you go up a few, you can come back down a few the same way.
03:25That can be really handy for finding an old command that you typed, especially
03:28if it's a long line, and just allowing it to be reentered another time.
03:33The other thing I want to introduce is a bit of the Ruby syntax.
03:35I am going to put a double quote, followed by Hello, and then a dot, and the word reverse.
03:41So now we are actually writing some Ruby code.
03:43We will talk a little bit more about what Hello is later.
03:46For now just know that it's an object.
03:48We have told that object to reverse itself, and this is the thing I want you to
03:52notice is the dot notation here, and the dot notation tells it to reverse.
03:57Then in order to get out of IRB, we simply type quit, and that takes us back
04:01to our command prompt.
04:02Now, there is one other thing I want to show you about IRB, which is if we do
04:05IRB and then --simple-prompt, there we go, --simple-prompt, then we get a
04:13simpler prompt, 1+1.
04:16Everything works exactly the same; we just have a much shorter prompt line at
04:20the end of each one.
04:21Some people like the longer one.
04:22It gives you line numbers and everything. The other one doesn't.
04:25It just sort of gets all that out of your way. So it's up to you.
04:28You may already be configured to use the simple prompt.
04:30If so, that's fine.
04:31But this will allow us to have either the simple prompt or the complex prompt,
04:35depending on your preference.
04:36I will type quit one last time, and that's all you need to know to get
04:39started working with IRB.
Collapse this transcript
Documentation
00:00Before we dive into learning Ruby, there is one last thing that I wanted to
00:03introduce in this Getting Started section, which is the documentation on Ruby.
00:07The best place to get the documentation is from the Ruby Documentation website,
00:11and that's www.ruby-doc.org/core/. Now, if you were just to go to the ruby-doc website,
00:19you will be able to find the core API for your version of Ruby directly
00:22from there, but core will take you straight there.
00:24So here I am on the ruby-doc website. The link that I was talking about is the
00:281.8.6 core. You will see that that's going to take us to the same place that we
00:31would have gone otherwise.
00:32So that's just going to be here, ruby-doc.org/core.
00:36This is going to be all of the different classes and methods and files that are
00:40available to us in Ruby, and we can do a search to find the things we want.
00:43This will all make a lot more sense to you as we start learning Ruby, but I want
00:46you to know where it is now.
00:48So for example, if I pick the class string, you will see that it takes me to a
00:51page about the strings and then I can pick a method like upcase here, from its
00:56methods, and we can see what it does, and it reports back that string upcase
01:00returns a copy of the string with all lowercase letters replaced with their
01:03uppercase counterparts, and then it gives me an example.
01:06So that's going to be the kind of information we can get to find out how to use
01:09these different methods inside the different classes of Ruby.
01:12Now, that same documentation is also available to you from the command line.
01:16So if we go into our terminal, we can type ri, which stands for Ruby
01:20Information, and then we can type in something like upcase.
01:24It will come back and it will report to us about upcase, and it will say ah,
01:27actually I have several different things called upcase, which one do you mean?
01:31You will notice here that it has String, then the pound sign, and upcase, and
01:35that's the format that it wants.
01:37When you see END, you will want to hit the Q to get back out of it.
01:41So let's try it again with String#upcase, and you will see that it comes back
01:47and it says the exact same information that we had on the website.
01:50The difference is this is stored locally on our computer.
01:53So if, for example, we are on an airplane and we are trying to remember how
01:56something works, we can just pull it up off of our laptop directly without
02:01having to have an Internet connection.
02:02So I will hit Q one last time.
02:04Let's take a look at another one, which is going to be ri Object#inspect.
02:11Now, I just wanted to introduce this idea of inspect to you.
02:13Remember, almost everything is going to be an object in Ruby, so this is going
02:16to apply to a lot of different things, and we can use inspect.
02:20It's going to return a string containing a human readable representation of the object.
02:24So just keep that in mind. We will be using inspect from time to time to just
02:28see what an object looks like in its human readable form.
02:32Now, a lot of times it's hard to represent a complex data structure as something
02:36human readable, but it will do its best.
02:38But I just wanted to introduce that other bit of Ruby before we go on.
02:41But the main thing to remember is that for the documentation, you can go to the
02:44ruby-doc website, or you can type in ri for Ruby Information to get that same
02:48information directly off of your computer.
02:50It's stored with your Ruby installation.
02:52Now that we have got everything installed and we are oriented a little bit to
02:55the way that the Ruby programming language is going to work, we are ready to
02:58actually start learning the syntax of the language.
03:01We will do that in the next chapter.
Collapse this transcript
2. Ruby Object Types
Objects
00:00In the introduction we discussed the fact that Ruby is an object-oriented
00:03programming language, and I have pointed out several times that almost
00:06everything in Ruby is an object, and that's one of its strengths.
00:10Now, in other languages that's not always the case.
00:12A lot of languages have something they call primitives, which are like the basic
00:15object types that we are about to talk about, but primitives don't have a common
00:19relationship to each other.
00:20In the case of Ruby, all of these object types that we are going to discuss are
00:25all related because all of them are objects.
00:27That's the fundamental building block that everything else is built off of.
00:31So keep that in mind in Ruby; everything is an object.
00:33Everything you manipulate is an object and everything that's returned by your
00:37manipulation is also an object.
00:39So what is an object?
00:40Well, we call it an object because it's rather analogous to an object that you
00:44would have in the real world.
00:46So for example, in the real world we would have an object that would be a
00:49classroom, that's a thing, and that could be modeled in Ruby as being an object as well.
00:54In the real world we would have students that would be in the classroom, and
00:57those students would also be modeled as objects, and each of the desk in the
01:01classrooms could be an object and so on.
01:02Now, in the real world, a classroom can contain many desks and have many
01:06students, who are sitting in a certain order, and we can move students around
01:10between the desks, have certain students who are maybe absent on a certain day.
01:13All those kind of complex behaviors we can use objects to talk about.
01:17It's really analogous to what we are used to in the real world, which makes it nice and easy.
01:21But objects can also be abstract.
01:24We could have an object for the communication that occurs between students.
01:27We could treat their conversation as if it was a physical thing.
01:30So it's not always just going to be an actual physical object that we are
01:34thinking of when we are modeling things in Ruby.
01:36Now, in programming terms an object is actually an instance of a class.
01:40We will talk a lot more about instances and classes in Ruby a little later.
01:44But using our example, each unique student would be one example of the more
01:48general classification student.
01:51In programming we would say that each student is an object or an instance of the class student.
01:56They are all unique but they have something in common too.
01:59Now that we understand that everything in Ruby is an object, let's take a
02:02look at these basic object types that exist in Ruby and begin learning to program with them.
Collapse this transcript
Variables
00:00In this movie, we're going to talk about variables in Ruby and I'm sure that
00:03you're going to think that I've already lied to you because I told you that
00:06everything in Ruby is an object.
00:08But here I am. I'm going to talk about variables and variables are not objects.
00:12They are a rare exception.
00:13It's kind of strange that we're going to start out talking about it, but we're
00:16going to use variables a lot, so we need to go ahead and cover it.
00:18Variables are just part of the Ruby language.
00:20Variables are going to be used to keep track of our objects and to give us an easy
00:24way to talk about those objects and reference them while we are programming.
00:27We can treat variables just like objects because once a verbal is assigned an
00:31object as a reference, it acts just like that object.
00:35So, a variable always either be undefined or will act like an object.
00:39So, variables will seem like objects even though they're not.
00:42Variables work pretty much like the variables that you had back in algebra class,
00:45except that we need to assign a value to them before we can begin using them.
00:50Let's take a look.
00:50I'm going to open up an IRB session and let's go ahead and use our first
00:55variable. We will just call it x, just like we had in algebra.
00:58But like I said, we want to assign a value to it.
01:00Let's try x+2, just to see what that gives us.
01:02x is undefined, it doesn't know what to do with it.
01:05We need to assign a value for it.
01:06So x=1. Now we can use our up arrow and go back to x+2 and now x has a value.
01:13So that's how variables are going to work.
01:14It just stores the object 1. 1 is an object.
01:18We'll talk little more about that in the next movie.
01:20But for now, just notice how x is a variable that is pointing to an object.
01:26Now, 2 is also an object, and 3 that gets returned by x+2?
01:31That's also an object.
01:33In fact remember when we said puts x+2 that nil that we got back is also an object.
01:39So, really and truly, everything is going to be an object in Ruby except for
01:43these variables which are just used to allow us to point to objects.
01:47Now, all programming language have a variable naming convention.
01:51A lot of variables have a start with the dollar sign in a lot of languages.
01:54In Ruby that's not true.
01:55All we have to do is have a all lower case, underscored name.
01:59So first variables equals 3, okay.
02:04That's a well named variable in Ruby.
02:07Now, we don't want to put mixed case. All right.
02:09You don't want to do something like this, like you do in a lot of languages.
02:12We don't want to put dashes in there.
02:14It needs to be an underscore and typically you would not run words together like that.
02:19We would go ahead and make it more readable like the English language by just
02:22putting an underscore in there, and that way it's nice and legible.
02:25We can quickly read our code and know what it's doing.
02:29So in the same way since Ruby is readable, we want to try for readability too.
02:33For example, we don't want to do aw_counter = 100. We want it to say
02:38articles_written = 100.
02:41So it's very clear right away what we're talking about. We don't have to sort of
02:46decrypt the name of our variable.
02:48So, give your variables good common sense names.
02:51Now lot of times in these tutorials I'm going to be trying to show you something
02:54quickly, so I'm going to use something like x or maybe I might just say var=1.
02:59That's fine because we're just doing this for a demonstration purpose.
03:02If I were writing an actual program, I would want something that gave me a
03:06little bit more of a clue as to what was happening in the program.
03:09Now, as I said, variables are references that can be assigned.
03:12So for example, a=100 and then we could have b=a. Now, if we ask for the result
03:19of b, which we can do just by typing a variable on a line, it will return the
03:23value that variable, the object that it points to.
03:26It's equal to 100 also.
03:27All right, it's not equal to a, because a is just a pointer to an object.
03:31So, b takes on that same reference and in fact if we do a = 50 now and we asked
03:37for b again, be is still pointing at 100.
03:41If you programmed in other languages before, this probably makes a lot of sense to you.
03:44There is one additional aspect of variable naming that I want to touch on here,
03:48even though we're going into a lot greater depth about it later on and that is the
03:52variable scope indicators.
03:54In addition to just having a lower case underscored word be the name of our
03:58variable, we can also put some additional characters in front of it that will
04:02let Ruby know what the scope or the variable ought to be.
04:05In other words where it should be available?
04:07Scope determines whether or not we have access to these variables from inside
04:11classes, methods, and other coded structures and we'll talk more about it once
04:15we introduce those structures, but it's kind of hard to show you examples when
04:18right now we only have our global scope to look at.
04:21So what we've been using so far are local variables, ones wherewe have nothing in
04:24front of it, and all you really need to know for now is that variable names can
04:29began with the $ sign or the @ the front of it in order to give it different scopes.
04:33So, $ sign in front of it would give it global scope.
04:36Putting two @ signs in front of it makes it a class variable.
04:39Putting one @ sign in front of it, it becomes an instance variable and we'll be
04:42working with these later on.
04:44For now just know that these are all legitimate ways that you can name
04:47your variable in Ruby.
Collapse this transcript
Integers
00:00In this movie we are going to take a look at the Ruby object type integers.
00:03Now, integers are just simply numbers, and numbers are mostly commonsense.
00:08But in Ruby, numbers are actually divided into two major categories.
00:12We have integers and then we have floating-point numbers, which are called
00:15floats for short, and they are better known outside of programming as
00:18being decimal numbers.
00:20Ruby is going to separate them out into two categories.
00:23Let's take a look at integers now.
00:25I am going to open up irb.
00:28We were working with integers before when we had 1+1 or we had x=2.
00:33Those are integers, and we are doing assignment with integers.
00:35It's just a basic number.
00:36That's what an integer is.
00:38We saw that we can do other operations.
00:40For example, we could have 4/2, we could have 4*2, we can have 4-2,
00:47those will all work for us.
00:48There's also an exponential operator, two asterisks together, and the result is 16.
00:54That's four to the second power.
00:56We also saw how we could do assignment, x=4.
01:00We can do an operator with assignment, plus equals 2, and notice what
01:05that gives us back.
01:06It gives us the result of the operation, 4+2. which is 6, but it also changed x at the same time.
01:13So that now x is going to be equal to the result of it.
01:17So it both incremented it and made the assignment.
01:20It's the same thing as if we had typed x=x+2. It does the exact same thing.
01:26It's just a shorthand to do it this way.
01:29We can do the same kind of assignment operator with all of these other things too,
01:32the division, multiplication, minus, all of those work the exact same way.
01:36Just put them in front of the equal sign and it will both perform the operation
01:40and do the assignment at the same time.
01:42It's kind of a nice feature.
01:43We can also use parentheses in Ruby, (1+2) *3.
01:49You see that it comes back with 9.
01:51So integers work pretty much the way we would expect them to work.
01:54Now, let's take a look at something else.
01:56We said that integers are objects.
01:57So let's do .class, and that will tell us what class it belongs to.
02:03Before I explain this, let's try another one, 123456789123456789.class.
02:11Now, notice that when I did one of them, its class was Fixnum and the other one
02:15was Bignum. Neither one was class integer, which is what we might have expected.
02:19It's because integers actually belong to one of two subclasses; they are either
02:23put into Fixnum or Bignum, both are subclasses of integer.
02:28The difference is only in the way that Ruby stores these values in memory.
02:31It uses more memory to store these bigger numbers, so it's going to reserve a
02:36bigger amount of space, but to keep it from taking up too much space all the time,
02:40it also has the smaller more efficient structure called Fixnum that it can
02:44use for smaller numbers.
02:46So we have Fixnum and Bignum and Ruby will switch back and forth as needed and
02:50so you will never need to worry about the difference. Just think of both of them
02:54as being an integer.
02:55You can try this out with a couple of things.
02:57If you want to multiply together two Fixnums, you can see how long it takes for
03:01you to get to be a Bignum.
03:02So for example, let's say x=1234* 1234*1234, and than x.class, Bignum.
03:14So you see it just switched back and forth between this and there wasn't a problem.
03:17Integers can also be negative, so -200 is a perfectly valid integer.
03:22200.abs is the absolute value.
03:25That will return the absolute value by applying the absolute value method, which
03:29we used in the dot notation we have seen before.
03:31We can also have 200.next.
03:33That's another nice method that we can apply to integers and it will return the
03:37next integer that comes after it.
03:39It's the same as if we would have said 200+1.
03:42That's really all there is to integers.
03:43Just don't be thrown by the Fixnum, Bignum distinction.
03:46If you look at the class, they are both considered integers.
03:49But if you keep that in mind, I think integers will be a breeze.
03:51But in order to really understand the way that Ruby handles numbers, we need to
03:56not just look at the integer class, we also need to look at the float class, and
03:59we will do that in the next movie.
Collapse this transcript
Floats
00:00In the last movie we talked about the first type of number in Ruby, which is an integer.
00:04In this movie we are going to talk about the second half, which are
00:07floating-point numbers, or for short, we just simply call them floats.
00:12Outside of programming you might simply call these decimal numbers or
00:15numbers with precision. Let's take a look.
00:17I am going to open up irb, and let's just try typing our first float, 12345.6789.
00:25It has a decimal number.
00:27This is a float, perfectly valid in Ruby.
00:30If we hit the up arrow and then type class after it, you will see it comes back
00:34and it tells us that it's a float.
00:36So this is what a float looks like.
00:38Notice the difference between x=10, which returns 10 to me, and y=10.0, which
00:45returns 10.0, and x's class is a Fixnum, while y's class is going to be a float.
00:54So it lets it know by putting that .0 after it that it should put it as a
00:59different kind of Ruby object.
01:01It basically says, look, the precision here is important to me.
01:05I care about the fact that it is exactly 10.0.
01:10The other one says it's 10, plain and simple, it's 10 and we are just going to move on,
01:14the precision isn't important.
01:16So notice if we now say x+1, it comes back and tells us that x=11.
01:21Then if we say y+1, it keeps the precision. Even though we added an integer to it,
01:28it says, oh, you know what?
01:29That precision was important.
01:31I have got a float here, so when I add one to it, I am going to keep track of
01:35that precision still, because it may be important down the line.
01:38Notice same thing if we say x+1.0.
01:42It now says, ah, the precision seems to be important.
01:45We had just 10, but the fact that we are adding a precise number to it means
01:50that we want to keep track of it precisely.
01:52Now, this leads us to talk about one of the biggest pitfalls that beginners can
01:57run into in the Ruby language, and that is if we say 10/3.
02:02Now, think about it for a second and what you expect that that's going to return,
02:06and then hit Return, and notice that it's not what you expected.
02:1010 divided by three is an integer divided by an integer, and it returned an integer to you.
02:16It basically said I was never told precision was important, so therefore it just
02:21returned an integer to you.
02:23Now, if we were instead to say well, 10.0/3 or 10/3.0, now it knows the
02:31precision matters to us, and so therefore it keeps the precision in the result.
02:35So this trips a lot of people up.
02:3710 divided by 3 or 10 divided by 6, it doesn't matter.
02:41It's just going to erase all the precision, everything that comes after the
02:44decimal point, and just return an integer to you.
02:47Don't let that trip you up.
02:49Now, we can also do some rounding of our own intentionally, 12345.6789.round,
02:58and it will round it, following the rounding rules.
03:00We can also tell it, "take it and convert this number to an integer."
03:04So we have this to_i method that will turn our floating point into an integer.
03:11What it does is it just removes all the precision.
03:13Notice it didn't actually do the rounding.
03:16It rounded down effectively by just removing everything.
03:19It's the same as rounding down.
03:21We can force it to always round down also and sort of indicate the fact that
03:25that's really what we mean by saying floor.
03:27It will always round down.
03:29Or if we always want to round up, ceil, which is short for ceiling, ceil, and
03:34that will always round up to the next number.
03:37So those are some nice methods that we can use on our floats.
03:40The main thing is just to make sure you don't get tripped up by this 10
03:44divided by 3 example.
03:46It's the one thing you really want to just get locked into your mind as you
03:50program in Ruby, so it doesn't trip you up down the road.
Collapse this transcript
Strings
00:00In this movie we are going to be talking about the Ruby object type for strings.
00:03Strings are sequences of characters.
00:05The name comes from the fact that the characters are strung together.
00:09They can be a letter, a word, a sentence, a paragraph, or even
00:12several paragraphs.
00:14In every case, it's still just characters that have been strung together.
00:17Let's take a look at how we can define and work with strings.
00:20I am going to open up a new irb session and we've already seen a
00:24string earlier, right? We had "Hello".
00:29That's just a simple string.
00:30It's between double quotes to let Ruby know that this is where the string starts and ends.
00:36We can also use single quotes the same way.
00:38'Hello', and that works just as well.
00:41We could have greeting = "Hello" and target = "world", single quotes or double quotes.
00:49It works exact same way.
00:50Notice that Ruby does a conversion for us here and returns its results always in double quotes.
00:55It's because it's the same thing; this is just the way the Ruby represents that
00:59value when it's output to us. It doesn't matter.
01:01It's stored as a string in both cases.
01:05We can also take strings and add them together, for example, greeting + " " + target.
01:12"Hello world."
01:14And we can simply add the strings together as if they were numbers.
01:18Now this is a common theme in Ruby where the syntax for something like addition
01:22is used in a commonsense way somewhere else.
01:25You can't actually add letters together, but it totally makes sense that the
01:28plus notation should smooch these together into new string in an additive way.
01:32For example, we can also multiply strings, "Gabba" *5 is going to be
01:38"GabbaGabbaGabbaGabbaGabba".
01:40Now notice that there is a difference if we do 1 * 5, which is 5, and if we do
01:45the string '1'* 5, which is going to return "11111" to us.
01:50So it's not going to convert strings into integers for us.
01:53We're going to need to tell it explicitly if we want to swap.
01:55Otherwise, it's gladly going to just multiply out that string for us.
01:59Now if we have a single quoted string like 'I'm escaped.' How is Ruby supposed
02:06to know where the string starts and ends?
02:09It's going to see the first single quote and then when it sees the second one,
02:12it's going to think that's the end of the string.
02:14So what we are going to need to do, we call escaping it, and that's putting a
02:16backslash in front of it, to let Ruby know this is a literal apostrophe
02:22inside of these quotes.
02:23It's not the end of the string, and notice it takes that away when
02:27it does its conversion to this double quoted version.
02:30The same thing is true for double quotes though.
02:32Let's say we had double quotes.
02:35"I said," we don't need to escape that anymore, "I'm escaped."
02:42We are going to need to put those backslashes in front of these two to let it
02:46know that those are literally meant to be quote marks inside of our string.
02:51Now it's going to keep those in there, when it returns that value to us.
02:55But it's a way of letting you know these are actual quotes inside there.
02:58Of course, if we also needed to have an actual backslash in there, we would
03:03put in two backslashes.
03:05Let's say we just put at the beginning here the number 3 slash slash and you'll
03:11see that it kept that in there, but this is a literal single slash.
03:16If we actually output that value, let's do it up here
03:19with a puts, you'll see that we get a single slash back,
03:26and we get our single double quotes here, when it actually outputs it. Okay.
03:31Now I know the 3 in front of it is nonsense.
03:33Now there is another very important difference between single quotes and double quotes,
03:38and that's the double quotes strings do some extra evaluation that
03:41allows us to use escape characters inside them.
03:43So for example, if I've puts " ", and inside I can put the escape character that is for a tab.
03:49So that's a tab and then I'll do an a and then another tab followed by b, and
03:55then I'll do a line return, which is nc, and then another line return nd.
04:01Notice what that puts, and there we go.
04:04You see the tabs are in there and the line returns are in there.
04:07If we were to trade that for instead having single quotes, notice now what we
04:12get back is as if that was just literal text.
04:16So that the double quoted version is going to do that extra evaluation.
04:20Even better than that though is that double quoted strings allow you to drop
04:25in variables to be evaluated. puts, and then inside double quoted strings,
04:32I want to say we'll put the pound symbol or the hash symbol followed by open
04:37curly braces, greeting, which is the variable we defined earlier, we'll close our curly braces.
04:43I'll put a space, and we'll do the same thing again for target, and now it will
04:48drop in those values.
04:50Let me put a period at the end.
04:51I want to say Hello world.
04:53So you see what it did.
04:54It evaluated that inside those double quotes.
04:57So now if we were to make those instead single quotes, you'll see that it took it literally.
05:04It did not do that extra evaluation.
05:06Now we can put any Ruby expression inside those braces.
05:10So, for example, puts, 1 plus 1 is equal to, and then inside here, let's ask it
05:18to tell us what is 1 plus 1? Here we go.
05:201 plus 1 equals 2.
05:23So it does the Ruby evaluation inside those braces and then puts the value inside
05:28the string and that only works with double quoted strings.
05:30Let's take a look at some of the methods we can use with strings. We saw
05:33one earlier, we had hello.reverse, and we also have capitalize, we also have
05:41downcase, downcase, of course we have upcase, and length, and you'll see it returns 5 to us.
05:54That's how long the string is, how many characters are in it.
05:57I think all those are pretty commonsense.
05:58The one thing I do want to show you though is that if we take Hello, and let's
06:03say we take the reverse method, there we are, Hello reverse, and then after that
06:09we ask it to upcase, you'll see that it does both.
06:12So we can daisy chain these methods together.
06:15So reverse.upcase.length, for example.
06:17Of course, the length obviously is still 5.
06:19It hasn't changed, but the point is that every time we start with our object,
06:25we apply the reverse method to the object, and then we return an object.
06:30Hello, backwards, and then that returned object gets the upcase method applied
06:36to it, and then the returned object from that gets the length method applied to it.
06:40So each time we're returning an object and applying a new method, and that's why
06:44it's so great that everything in Ruby is an object is because we can do this
06:47kind of thing to it.
06:48And of course, daisy chaining these methods together applies to all objects in
06:52Ruby, not just strings.
Collapse this transcript
Arrays
00:00In this movie we are going to talk about the Ruby object type for arrays.
00:04If you're familiar with arrays from other programming languages, Ruby arrays
00:07work very much the same way.
00:08But if not, let's first talk about what is an array.
00:11An array is an ordered integer- indexed collection of objects.
00:15That's a very fancy way of saying that we can take objects and put them together
00:18in order, and keep their position in the same order, and we can refer to those
00:23objects by their positions.
00:25That's what that integer-indexed part is.
00:27We can say give me the first object, give me the fifth object, and so on,
00:31because they are going to be indexed according to what position they hold.
00:34One good way to think about arrays is they are like those expanding file folders
00:38you get that you might put your bills in, and you might put your electric bill
00:41in the first pocket, and your phone bill in the second pocket, and your mortgage
00:45payment in your third pocket and so on.
00:47You have a preset order, and you can put things in and out of pockets.
00:51You can say put this in the third pocket or take that out of the fifth pocket, and so on.
00:55That's the way that arrays work.
00:57And the file folder is a good analogy, because some pockets can be empty.
01:00So we could have something in the first pocket and the third pocket, but not in
01:04the second pocket, and that would just be an empty one.
01:06In our case, it would be nil when we are working with Ruby.
01:09Now the things that can go in an array are any kind of object, any object at all.
01:14That's strings. That's numbers.
01:16That's more arrays.
01:17That can be larger or more complex objects and classes that we are going
01:21to learn about later.
01:22It can be mixed types as well.
01:24We don't have to just have an array of strings or numbers. We can mix them together.
01:28Now arrays are going to be very, very powerful and useful for us, and we are
01:31going to be using them a lot, especially when we are start working with lots of data.
01:35Imagine for a moment that we have an accounting program that has an array of all
01:38the customers that have come to our shop, and we can add to or select from each
01:43of those customers in that array.
01:45Then each one of those customers could also have an array of items that they
01:48purchased from the store or payments that they've made, and we can add to and
01:52select from those as well.
01:54And it will keep all of that data organized, and we'll be able then to move
01:58to the data one item at a time, either searching for records or sorting
02:02records, that kind of thing.
02:04Once you put into practice, I think it will become very clear.
02:07So I am going to start up by opening up irb and once I am in there, I am going
02:11to just create a new array, and I am going to assign a variable data_set equal to,
02:15and for our array, we use the square bracket notation.
02:19Open square brackets and close square brackets, that's an array.
02:21In fact, this is an empty array that I've specified, and that's perfectly
02:26legitimate. I can do that.
02:27It's an array with nothing in it, empty pockets.
02:30Then I could also put things in the pockets.
02:32Let's just drop in here, and let's put in a couple of strings, a, b, c, and now
02:40it holds those together, and it keeps them in order, so they will always stay in that order.
02:45And we can pull certain items out of the array to work with them by asking the
02:50array to return a certain item.
02:52So data_set, and then inside parenthesis immediately after the data_set with no equals.
02:59We are going to specify the position that we want.
03:02So I am going to say position 1, and notice that returns back b to me.
03:07This is a very important thing about arrays.
03:09If you've never worked with arrays before, this will take some getting used to.
03:12If you have, I am sure you're already familiar with this.
03:14All arrays are indexed starting with zero, so a is not in position 1. a is in position 0.
03:23So in order to get that back, we'd asked for data_set 0.
03:26That gives us a, or if we would've asked for 2, we'll get back c. Go ahead and
03:32notice that if we asked for 3, it tells us nil.
03:35That's because even though there's nothing in that fourth pocket, the third index,
03:39so it just returns nil to us. It just says there is nothing in it.
03:42It's a nice feature of Ruby, that it doesn't give us an error because we've
03:45requested something that's not in our array.
03:48We don't have to check and see how long it is.
03:49It just says there's nothing there.
03:51I have no value to give you.
03:53Now we can set values the same way.
03:55Let's go ahead and let's just set our position 0 equal to, we'll make it d.
04:02So it returns d to me.
04:04That's the return value of the operation.
04:06If we want to see what's actually in the data_set, we have to once again ask for
04:11data_set, and it will return the entire thing.
04:13We see now that a has been replaced with d, so we said, okay, in position 0, put d,
04:19which of course is going to displace the a, so it gets thrown away, and the d
04:24goes in there instead.
04:25There is also another nice operator, which is the Append operator, and the symbol
04:30for it is two less than signs together.
04:33If we do the less than less than and then another string, what that does is
04:37it appends it on to the end and you can see it returned as its return value, the full array.
04:42So now we have d, b, c, and then e.
04:46If we wanted to take a value out of the array, let's go back and just make
04:51value 1 be nil, and then if we ask for a data_set again, you'll see now it
04:57holds that first place with nil, all right, which is nothing, and that's how it
05:01knows that there's something in pocket 0 and something in pocket 2, but
05:04nothing in pocket 1.
05:06Now that doesn't clear out the whole array.
05:08If we wanted to actually clear the array, we have a couple of options.
05:11One is we can do data_set clear, and that returns an empty array.
05:15Let's do data_set. You'll see that it is empty.
05:18The other we'd have done the same thing is if we'd done data_set equals, and
05:22just set it back to an empty array, just like we did to initially start.
05:27Now notice though if we said data_set equals nil, that's a different thing.
05:32Now it's no longer an array.
05:34Let's go back here.
05:34Let's do this data_set, and then data_ set.class, you'll see it's an array.
05:40If I said data_set equal to nil, and then ask for its class.
05:43It comes back and says the class is nil.
05:45So it's actually a different thing, an empty array, and having nothing are
05:49two different things.
05:51Now that we know the basics of how to create an array, how to put items into and
05:55out of an array, there are lot more things we can do with them.
05:58They're really powerful, so much so that we're going to talk more about how
06:01we can manipulate arrays in the next movie.
Collapse this transcript
Array methods
00:00In the last movie we saw the fundamentals of creating an array, putting objects
00:04into it, and taking objects out.
00:06But there is a lot more that we can do to manipulate with arrays.
00:08So I want to spend another movie really looking at some of these array methods,
00:11to see how they work.
00:12I am going to open up irb, and let's go ahead and just create an array.
00:17I am just going to call it array = 1,2, 3,4,5, and I am going to create another one
00:24I will call array2.
00:26I know it's not a very descriptive name, but for our purposes this will work.
00:30I just want to show you that this is 1, and let's put in 2, and then 3.0, and
00:37then while we are at it let's go ahead and put in a, b, and last of all, let's put in dog.
00:46There we go.
00:48I want to show you, first of all, with that array2 that we can mix these types
00:51in there, and the array doesn't care.
00:53We saw how we can return different values.
00:55It works exactly the same way with the mix types.
00:59Now, we have two arrays that we can work with.
01:01The first thing I want to show you is that we can do inspect, array.inspect.
01:06You can see that it just returns back to me the array, which is a nice way to
01:11sort of see it and see what's going on.
01:13Now, we can just say simply array and that returns the value of the array, but
01:17that's not a string.
01:19The one above it is actually a string.
01:20You see those double quotes.
01:21So when we are inside a program and we are programming. We want to be able to
01:25put that version of it.
01:27Let's try puts array, and you will see what it gives us.
01:31If we do puts array, that's what it gives us.
01:33If we do puts array.inspect, it gives us this.
01:37So just keep in mind that you can use that to sort of peek at what's inside your array.
01:40That's especially useful if you have got something like this complex
01:44array that's in array2.
01:47If we were to just simply do puts array2 by itself, you will see that it gives
01:51us this, which doesn't really show us the structure. a and b are just listed out
01:55on separate lines, when in fact they are an array within the array.
01:59There is also another version that we can use which is let's do array2 to string.
02:05So 2_s is turned into a string.
02:09That just smashes everything together.
02:10So it doesn't give us this nicely formatted string that inspect gives us.
02:14Instead it joins them together.
02:16In fact, it's the exact same thing as if we do join.
02:19The difference is that with a join, we can also specify what we want to join it with.
02:23So I will use a comma space and now it will join them together and put
02:30commas between them.
02:32Incidentally, we can do the same thing in reverse.
02:34Let's say we have x = and it's a string, 1, 2, 3, 4 and 5, and we could say y =
02:41x.split, and split it on the commas.
02:47So now it takes the string.
02:50Every time it finds a comma, it says, "ah, that's a new element" and it turns it
02:53into an array for us.
02:54So it returns an array, and now y is equal to that array.
02:58We can also do reverse on our arrays, and you will see it just simply reverses
03:02the order like you would expect.
03:03It's not just for strings.
03:05Let's go back to our original array here, 1,2,3,4,5, and let's put at the end,
03:10array, we will do the append that we learned before, and at the end we will append a 0.
03:16So then we got 0 at the end.
03:17Now we can say array.sort, and it will sort our array in order.
03:22Now, we can't sort mix types, not using just a simple sort.
03:26We can learn more complex ways to do it later.
03:28But when I have that very complex array that has some floats, and some integers,
03:32and some strings in there.
03:34It's not sure how you want to sort that.
03:36There is no simple numerical order or alphabetical order that it can follow.
03:40So we would have to write something more complex and we can learn to do that.
03:42There is also unique. Let's say array.
03:46Let's again put at the end of it.
03:47This time we will put a 3.
03:50So you see that it has now got this 3 at the end, so it has two 3s.
03:53I can say array.uniq for unique, no 'ue' at the end, and it will return to me an
03:59array that has no duplicates in it.
04:01Now, it didn't actually change the array itself.
04:03It's not the same as when we appended it on, it actually changed the array.
04:07This just says return me another version, a new array that has no unique values in it,
04:12while leaving the other one alone.
04:13In fact, if we would do unique with an exclamation point at the end, it would
04:18actually change it in place.
04:21So there we go, array.
04:23Now it's permanently changed.
04:24It has been deduped.
04:26Now, we saw how we could set values to nil earlier.
04:30We also have array.delete_at, and let's say delete at position 2, and remember
04:37that's going to be the third item.
04:39So it returns what it deleted.
04:41It deleted number 3, so 3 was returned.
04:44If we take a look at the array, you will see it didn't set it to nil. Instead
04:49it pulled it out of the array and shifted everything over.
04:52So it actually removed it from the order completely.
04:56The other version left nil there as a placeholder in that position 3.
05:00Now, that's all great if we know the position, but what if we don't know what
05:03position something is at, and we want to delete something?
05:06We can also just use delete by itself.
05:09Let's say we will delete number 4 and now it returns 4 to us.
05:14But if we ask for the array, it went through and it found the number 4,
05:18not position four, the number 4.
05:20Now, the fact that both of these deletes return the value that's being deleted
05:25is nice, because we can sort of catch it as it's coming out of there.
05:27We can say pull it out of there, and while it's coming out, let me store it in
05:32another variable that I might want to use.
05:35We saw how we could have array with the append.
05:37We could append something at the end. Let's say 3.
05:40We can also do the same thing using array.push.
05:44So we will push something onto the end.
05:47Let's push a 4 onto the end. There we go.
05:50We can do array.pop and it will take the last element off of the array and
05:55return it just like the delete_at did.
05:57But it basically takes whatever is in that last position and pulls them out of there.
06:01We have the same thing with shift and unshift that we will work with at the beginning.
06:05So let's do shift first, which will return the 1, and then there it is.
06:11Let's do unshift now.
06:13We will put back on the 1.
06:14You can see the 1 goes back on there.
06:17There is a lot more to learn with array methods and you can take a look at that
06:21Ruby documentation to see what else is there.
06:23The one other thing that I want to show you is that we can also add arrays together.
06:27So array + and let's make a new array here which is going to have 9, 10, 11, and 12 in it.
06:36You will see what it gives us back is that it takes the first array and just
06:40adds those other elements on there.
06:42Just an additive property to make one new array.
06:44It didn't change the original array. I would have to store that if I wanted to
06:47capture it and say new_array = array + and I will just do that for now.
06:56We also have the same thing with array -. So there we are now.
07:00It has subtracted out those.
07:02We could also do, for example, array - 2 and that has the same effect as if we
07:06had done a delete searching for 2.
07:08I think that's enough array techniques to get us started.
Collapse this transcript
Hashes
00:00In this movie we are going to take a look at the Ruby object type for hashes.
00:03Before we start with hashes, you will want to make sure that you have a good
00:05understanding of arrays, because hashes are going to be very similar.
00:09Hashes are an unordered, object- indexed collection of objects.
00:14So notice, first of all, that where an array is an ordered collection, a hash is
00:18an unordered collection.
00:20That's a very important difference.
00:22We cannot count on the order that things are going to be stored in a hash.
00:26And instead of being indexed by their position and keeping track of the number,
00:32instead we are going to keep track of them using an object.
00:35We call this a key-value pair.
00:38We have one object that's the key and it references a second object that's a value.
00:43If you think back to the expanding file folder metaphor that I gave you when we
00:46were talking about arrays, well, hashes work a little bit more like hanging file folders.
00:51They are not in any certain order.
00:53They can be rearranged.
00:55Each of those file folders is going to have a label on it, and that's how we are
00:59going to find information.
01:00Since we can't know what order it's in anymore, now we are going to just thumb
01:04through those file folders in our hanging file folder until we find the label
01:08that corresponds to what we are looking for.
01:10So instead of saying well, our phone bill is in pocket one and our electric
01:14bill is in pocket two, instead we will say find the thing labeled phone bill
01:20and pull out its contents.
01:21Its contents will be the value.
01:23So that's a key-value pair.
01:25So both an array and a hash have a very good purpose.
01:28When we want to preserve the order and the order matters to us, we want to use an array.
01:33When it's not so much the order that matters, but we want the convenience of
01:36having that label, and we want to be able to refer to things by label instead of
01:39trying to remember what was in pocket number seven, I can't remember.
01:44Well, we can put a label on it by using a hash.
01:46So that's the two differences.
01:48One is going to be labeled, which will be the hash, and the array will
01:51preserve the order.
01:53Incidentally, in a lot of other programming languages, hash is often referred to
01:56as being a dictionary.
01:57So if you are used to calling it a dictionary in another language, Ruby is going
02:00to refer to it as a hash.
02:02Let's try creating one.
02:03So I am going to open up irb. I am going to start out by creating an array.
02:08So we can make an example here.
02:09I am going to make an array.
02:11It's going to be Kevin, Skoglund, and male, blue for my eyes, and blonde for my hair.
02:22So there we go, now we have an array that describes a person.
02:24Well, that's a little bit cumbersome if we want to remember, oh, blue, was that
02:29the color of clothes he is wearing today, or is that the color of his eyes?
02:32Is blonde the color of his hair or the color he wishes his hair was?
02:36It's a little vague as to what things are.
02:37So labels become important.
02:39So instead we want to use a hash, and a hash, instead of having those square
02:43brackets is going to use curly braces, and that's how we will know that it's a hash.
02:47That's how we can recognize it right away is that it uses those curly braces.
02:51We are going to have key-value pairs, and we are going to structure our
02:54key-value pairs like this.
02:55We will have first_name.
02:58And that's an object.
02:59It's a string, and it's going to refer to Kevin. So there we go.
03:03We have a key and a value, and we have this equals greater than sign that points
03:08from one to the other.
03:09So that lets us know that this is the label first_name that applies to Kevin.
03:13Now we can keep going with the rest, last_ name, and we will point that at Skoglund.
03:18There we go. Now, you could keep going and do the rest of them for a time. I am not going
03:22to type them all out.
03:23I am just going to leave it at that, because it will allow me to show you that
03:26we can use the same notation that we used when we were working with arrays, but
03:31instead of providing the index that we want, we are going to provide that key.
03:35So it will be the string, first_name.
03:38That's the thing that points at the first_ name that's inside our gash.
03:42If we wanted the last_name, the same thing.
03:44It's a string that we are asking for.
03:46So it's object-indexed.
03:48Instead of being integer- indexed, it's object-indexed.
03:51We are asking for that object back.
03:53Now, even though we won't use it as often, I want to go ahead and show you that
03:57we can also use the index method, and we can ask for the reverse.
04:01We put this inside parentheses, but we use the index method and tell it return
04:05Kevin and it will return the key to us.
04:08We said find the value Kevin and return its key.
04:11So it's the reverse of what we are trying to do.
04:14Sometimes that trips beginners up, because they are so used to using keys to
04:17find things that when they finally say, oh, you know what, I wish I could look
04:20something up by its value, they are not sure how to do it.
04:23So we can use index to do it.
04:24Return the index of the value Kevin.
04:27I also told you earlier that we could have a mixed objects in arrays.
04:32The same thing is true for the keys and the values that are inside a hash.
04:37We could have the number 1 that points to a, b, c and then a comma and our next
04:46one, which will be 'hello', which is a string that's going to point to 'world'.
04:51Then let's make our next one actually be an array. There we go.
04:56That's going to point to a string.
04:58We will just make it 'top', just sort of a nonsense word there.
05:01So now we have a mixed hash.
05:04Notice that it switched the order around.
05:06The order is not important.
05:07We can't count on it being in any particular order.
05:10What it returned to me may always be the same thing.
05:13That's just because of the way it happened to be stored in memory at
05:16this particular moment.
05:17We can't count on it not moving around.
05:19We have to refer to things by label.
05:21So we could ask for mixed, and then 1, and it will return not the first element,
05:27but the thing with the label that is 1.
05:30Same thing we saw how we could do 'hello' earlier by doing a string.
05:33So instead, I will just show you that we could also put 10, 20 and that will be
05:38the array that we asked for.
05:40And it says, "oh, let me see if I can find that as a label," and so it says "ah,
05:43here is the array [10, 20] and so I will return the value, which is top."
05:49There are a lot more things that we can do with hashes.
05:51I am just going to show you a couple of other quick ones.
05:53Let's say we have mixed.keys, will return all the keys, and mixed.values, will
05:58return all of the values.
06:00It will turn it into an array when it does that.
06:03We could also have mixed.length.
06:05I don't know if I showed you earlier, but you can use length on an array for the same purpose.
06:09Size is also synonymous with that.
06:13We can also use a mixed.to an array.
06:18That's to_a, and it turns all those key-value pairs into array pairings.
06:22So each key-value pair is its own array.
06:26Last, we also have mixed.clear, and that will just turn it to a simple empty
06:31hash, or we could just do mixed equals, and just empty curly braces and that
06:37will also then just set it back to an empty hash.
06:39So the last thing that I just want to show you is just if we want to set a
06:43value inside one of these hashes, besides just creating it, we do it just the
06:46same way that we do with an array.
06:48We use the square bracket notation and then we put the label that we want.
06:52Even if it's not something that's in there already, it doesn't matter.
06:55Equals and then whatever it is, so male.
06:58You will see now it returns male to us, but if we ask for person again,
07:02it actually has added that key-value pair to it.
07:05So there is a lot more that we can do with hashes.
07:07I think this is enough to get us started.
07:09Take some time and make sure that you understand both arrays and hashes and
07:12the difference between them, because we are going to be using them a lot when
07:15we program in Ruby.
07:16It's going to be really important that you feel like you have a good handle on things.
07:19Don't worry if you have to look up a lot of the methods that go with them.
07:22That's very common.
07:23There are so many things you can do with them.
07:24You are going to make frequent trips to the documentation to remember all the
07:28powerful things that arrays and hashes will let you do.
Collapse this transcript
Symbols
00:00In this movie we are going to talk about the Ruby data type for symbols.
00:03And symbols are one of the most misunderstood types by most beginning Ruby programmers.
00:07So I want to make sure that we have an understanding of it.
00:09On one hand symbols are going to seem a lot like strings, but they are not.
00:13And sometimes they are going to seem a lot like variables, but they are not.
00:16What asymbol is, is a label that's going to be used to identify a piece of data.
00:21Now a string can also be a label too.
00:23We just saw that when we were working with hashes, right?
00:25So, why do we need symbols?
00:26Well the reason is because a symbol is going to be stored in memory one time.
00:31Whereas a string is going to get stored each time. Let's take a look.
00:35I am going to open up a irb session.
00:38And the way that we type a symbol is that we simply use the colon and than the name.
00:43And the name works the same way the variable names would.
00:46So we can have for example test.
00:48That is a symbol, or this_test.
00:52So, that's a symbol that we have just declared.
00:54It's an simple object.
00:56Now to show you how the symbol test is different from the string test.
01:01Let's say this_test and then let's ask for it's object ID.
01:05This is a very rarely used Ruby function.
01:08But we can ask for the object ID of something, and you see it gives me back a number.
01:12And that's why it's not used very often.
01:13It's a little bit meaningless to have this number.
01:15But notice that when I do test. object_id, it has a different object ID.
01:22Well, let's do the test. object_id again for a string.
01:26I have a different one.
01:27Third time, three different ones.
01:28And it's because it created a new string called test, right?
01:31It didn't reuse this old one.
01:33It's a whole new object.
01:34This is one object, and this is the second object.
01:37Now, let's go up and let's do the symbol again.
01:40Notice that this time it's the same one, because the symbol is stored one time
01:44in memory, and then it goes back and reuses that same symbol, because it's just a label.
01:49Now for that reason symbols are going to work really well inside hashes.
01:53So, let's say hash = first_name Kevin and last_name Skoglund.
02:05Now that's a great way to label our people, because then if we have another
02:09person, who will use that same label, first name, again.
02:12We don't have to create a new bit of memory to store it in.
02:15So we conserve the amount of memory our computer has to use to run our program.
02:20Where if we use a string for the first time, like we did back in the hash movie,
02:23every time we created a new person, it would create a new Ruby object and
02:28store that in memory.
02:29So when we really want something to be a label, which is definitely what we want
02:33with hash, we are going to want to use that symbol most times.
02:37Unless we really need to use the string, go ahead and use a symbol.
02:40Now there is an important point though.
02:41Watch if I now ask for hash and ask it to give me back it's first name.
02:46It goes back and says no, sorry, don't find that label.
02:50That's because it doesn't have anything that has a string object called
02:55first name as a key.
02:57What it has is something with a symbol.
03:01So it can tell the difference between them.
03:04And some of you may have said, wait a minute.
03:06Let's say that I have four or five people and I have four or five first names.
03:11Each one of those has a different object as the label.
03:14And it's a different object every time.
03:16How does hash then still return the same thing to me?
03:19This is because when hashes have a string as the key, it does say well, it's good enough.
03:25It doesn't have to be the exact same object.
03:27It has to have the same value.
03:29It has to be of the same class and have the same value.
03:31Not necessarily be the exact same object.
03:34The other thing that I don't want you to be confused about is that symbols are not variables.
03:39So if we have something like test = 1, it comes back and says nope, sorry, I don't
03:44know how to do that. That's a label.
03:46So up here hash is the variable.
03:49It's a hash that has the label first name.
03:52So you may feel like this is a variable, but it's actually hash that's the variable.
03:57First name is just the label that's in the hash.
04:00So the rule of thumb is if what we are talking about really is a word and if
04:04the sequence of a character is important, or if it is going to be for output,
04:08then we are going to want to use a string.
04:09But if it's a label that's being used to identify a piece of data, or as we will
04:15see later on, to pass a message around between different parts of our program,
04:19we will want to use a symbol.
Collapse this transcript
Booleans
00:00In this movie, we are going to talk about the Ruby type for Booleans.
00:03Now if you have done programing before, this is all going to be very familiar.
00:07If not, you will just want to take a second to understand that a Boolean is in
00:10simple terms just going to be True or False.
00:13Something that's one or the other.
00:15It can't be anything else.
00:16It's either going to be true or it's false, and we are going to use this
00:19for doing comparisons.
00:21So in a program we might say for example, if X=1, then output X, or if X is not
00:29equal to 1, then output something different.
00:32That's the kind of thing we are going to be wanting to work towards in our
00:35control flow, which we will get to in a little while.
00:37For now, we just want to focus on the conditional part of that, which is a Boolean.
00:40In order to do that, we are going to need to know some comparison and
00:43logic operators in Ruby.
00:45The first of these is the equal to operator.
00:47That's probably the most common one you will use, and what we would use is for
00:51example X and then = = 1.
00:54And that would say well, if X is equal to 1, it's a test whether or not it's true.
00:59That's very different from X=1, which does an assignment and it sets the value
01:03of X=1. We are not doing an assignment here. We are comparing it.
01:07So you want to be careful when you are writing these that you use the double equals sign.
01:11That throws off some beginners.
01:12It can especially be a problem, because doing an assignment like that will
01:16almost always return true.
01:19Therefore, your test case will return true, even though what you meant to do was
01:23to compare and find out whether or not it was true.
01:26Then we have less than greater than, less than or equal to, greater than or
01:29equal to, I think those are all pretty self explanatory.
01:32Then we have got the Not Operator.
01:34Now the Not Operator is a logical operator and it says that something is not the case.
01:39We can put it in front of just about anything, including just variable names.
01:43So !X, means that X doesn't have a value.
01:46X is either unset or it's been set to false or nil or something like that.
01:52That would also return false.
01:54Then we can see we put it in front of the Not Equal.
01:57That's another very common one.
01:58If X is not equal to 1, then we use the !=.
02:03And then we have these other logic operators And and Or, the double ampersand or
02:07the two upright pipes, one after another.
02:09Find that on your keyboard.
02:10It's an upright line followed by another upright line. We call those pipes.
02:14In this case it's going to be the Or operator.
02:17So that way we construct one set of comparison and then say and something else
02:22is also true, or case number 2, or case number 3 is true. Let's try it now.
02:28I think it will become clear.
02:29I am going to open up a new irb session, and let's start out by just following
02:34that simple example. Let's say X=1.
02:37So now we can say X==1 true, and it returned true to us.
02:42Now true is actually an object in Ruby. Remember I said everything is an object.
02:47This is our Boolean. true.class is the TrueClass and false.class is going to
02:55return the FalseClass.
02:56So those are actually objects as well.
02:58So if we say X!=1, of course that returns false, because X is equal to 1.
03:03Of course, we can say is X<3? Yes, it is.
03:09Is X>3? No, it's not.
03:12Let's try putting just the exclamation point in front of X. We will see that it
03:15returned False because there is an X. With an exclamation point in front of Y,
03:18it says, nope, Y wasn't set. Y=false.
03:23Now, !Y=true. It's the reverse.
03:28Think about that for a second.
03:29Logically sometimes you get in little tangles, and you have to kind of stop and
03:32think your way through it.
03:36So it would have returned False if we just had Y. We are telling it to
03:38find the reverse of that, which is True.
03:41Let's try out some of our And and Or operators.
03:44So if 1<=4 and 5 <=100, True, because both conditions were true on both sides.
03:59Now, notice I don't have parentheses around this. If things start getting really complicated,
04:03you need to group things together,
04:05you can put parentheses around your Booleans.
04:07Let's say if this is true, and let's do another one here where we will say 100
04:12is equal to or greater than 200, which of course is not true.
04:18So now, it tries to go through all three of them.
04:21The first one, it says that's true, and the second one, that's true, and
04:28the third one, oops! That's not true.
04:30So the requirement was for all three to be true.
04:33This one to be true, and this one to be true, and this one to be true.
04:36And since they are not, the whole thing returns False.
04:39So notice the way it works its way down the chain.
04:42We can do the same thing with Or.
04:46Let's put an Or operator in here for each of these. Here we go.
04:53Now, it comes back and it says True, because 1 <= 4, that was true, Or,
04:58well, it doesn't matter what the rest is.
05:01It doesn't even have to keep going, because the first one is already true.
05:05So one of these things has to be true.
05:07Let's just try and change that real quick.
05:10Let's make this into, let's say 16 < 4. Still true, because it says well, is 16 < 4? No, it's not.
05:18Or, maybe 5 <= 100.
05:21Well, that is true.
05:22And it stops right there, because it has found one of these that's true.
05:26Let's go ahead and make that not true, just so we can see what happens.
05:31Now it returns False, because none of those things are true.
05:35If this Or this Or this, and none of them were true, so it returns False.
05:40Now, there can be a lot of different methods that we can use that will
05:43return Booleans to us.
05:45For example, x.nil?
05:47No, it's not nil. y.nil?
05:52No, it's not either. Let's try z.nil?
05:56Undefined local variable.
05:57But if we had said, z=nil, and now do z.nil, we get back True.
06:03We could also use something like Between.
06:05Let's say the number 2, between, and let's put in two values. Is it between 1 and 4?
06:13Actually I need a question mark.
06:14A lot of these Booleans are going to have question marks in them, because it's
06:17answering a question and that helps you to know.
06:19There is no problem in using question marks in the names of methods inside Ruby.
06:24You won't want to use them in your variable names, but they are in the method
06:27names a lot of times.
06:28So is it between them? Yes.
06:30Is it between 3 and 4? No.
06:34A couple of more quick ones that we can do.
06:35If we have an array, let's say array 1,2,3 .empty? Is it empty?
06:41No, it's not empty.
06:42If we just had something by itself, then of course it is empty.
06:46We could also do 1, 2, 3, does it include 2? Yes, it does.
06:54Does it include 5? No, it does not.
06:57We could do the same thing with hashes.
06:58We can have has key and has value.
07:00Let's just try one of those real quick, and I will make just a real simple hash here.
07:04There we go, 1, and b will point to 2, and then we will take that hash and we
07:11will just say does it has key a? Yes, it does.
07:17Does it have key symbol a? No, it does not.
07:21We could do the same thing with has_value.
07:24Does it have the value 2? Yes, it does.
07:29So there are going to be a lot more comparisons that we can learn to do in Ruby
07:33and a lot more of these methods that are going to return Booleans.
07:36The main thing is to understand the basic concept and understand how you can
07:40use these comparison and logic operators to construct a Boolean expression.
Collapse this transcript
Ranges
00:00In this movie we are going to talk about the Ruby object type for ranges.
00:04Now a range is going to typically be a range of numbers.
00:07Right, so let's say numbers from 1-10.
00:10Well, we could have an array that would contain all of those numbers or we
00:13could simply have a range which will say well, here is the starting point and
00:16here is the end point. It's from 1-10.
00:17Specially if we have something like 1- 1000, it makes a lot more sense to have
00:21something that just tells us the start and end point instead of trying to
00:24construct an array or something that has all 1000 numbers in it.
00:28We can use a range instead.
00:30And there is two kinds of ranges.
00:31There is the inclusive range, and the exclusive range.
00:35And the notation is right there.
00:36That's how it works.
00:37It's just the first number and then either 2 or 3 dots depending on which
00:41one you want to use.
00:42Inclusive would be the numbers 1, 2, 3, 4, 5, 6, 7, 8, 9, 10.
00:47Exclusive range would be 1, 2, 3, 4, 5, 6, 7, 8, 9.
00:52It would exclude the last value.
00:54So it would be one up to but not including 10.
00:57Now when you're programming in Ruby, you'll find that the first one,
01:00the inclusive range, is much more common. Why?
01:03Because you can see both of the values that are included so that makes it nice
01:07and clear what's included in it.
01:09And it's one less character to type.
01:11So that saves us a little bit of typing as well.
01:13But if you need to use the exclusive range, it's there and you can use it.
01:17You could also just do 1..9, which I would say is probably more common and what
01:21I would recommend to you.
01:22Let's try them out, see how they work.
01:23So I am going to open up irb and let's start by just trying out that simple
01:29inclusive range, 1-10.
01:30You see that it returned 1..10 to me.
01:33It didn't return all the numbers.
01:35It didn't expand it.
01:36It kept it as a range.
01:37That's actually a range object.
01:39x =1..10 x.class is a range.
01:45Now I want to show you something here. 1..10.class is gong to give me some problems.
01:50I set the value x equal to that and then ask for its class,
01:53that's not a problem. The problem is with the dots.
01:56The dots get a little bit confusing to Ruby and so it says, "oops, I don't
01:59know what you mean."
02:00If you put simply parentheses around it then it clears it all up.
02:05And then it knows exactly what you mean.
02:06So just be careful with that, with ranges.
02:08If you try to apply one of these methods directly to the range, it will give you some problems.
02:13If you assign it to a value or if you put it in those parentheses then
02:17it will be all cleared up.
02:19We have a couple of methods that we can use here. We have x.begin that will
02:24return the beginning of the range, and end that will return the end of the range.
02:30x.first is another one, and x.last, and those essentially do the same thing.
02:37Now let's try another one.
02:40Let's say y = 1...10, another range but this one is now exclusive range.
02:45Let's ask it for its y.begin and y.end.
02:50Notice that it still reports the same beginning and end, even though it is
02:56exclusive and inclusive.
02:57So be careful with using begin and end on your ranges because it may not be what
03:02you expect it to return.
03:04To show you that they are actually different though I can say, for
03:06example, x.include?(1). Yes, it does.
03:12Does it include 10? Yes, it does.
03:15But if I now try that on y. Does y include 10? No, it does not.
03:20Now what if we actually did want to expand this?
03:24What if we wanted to expand it out so we had all of those numbers 1 through 10
03:28in an array that we could work with.
03:29Well, there is a nice way that we can do that, if we use the array notation,
03:34which is square brackets.
03:35We will put our x inside of it and in front of the x we will put the asterisk.
03:40We call that the splat operator.
03:42So the splat operator in front of it and we will just say z is going to be equal to that.
03:48And there is what it returns.
03:49It breaks it all out.
03:50So x is still equal to just the range but z is now equal to all of those
03:54numbers. They have just spread it out and expanded it into all of its values.
03:59Now numbers are not the only thing that we could have as ranges.
04:01That's the most common thing we will use.
04:02But let's say that we have 'a'..'m'.
04:10So a to m. Actually let me do that again and we will just set alpha equal to it,
04:16alpha.include. Does it include g?
04:21Yes, it does include g because g is in that range between those letters.
04:25And we can do the same thing if we have that splat operator, alpha, here we go.
04:30And that returns all the letters a through m.
04:34So it's a good shorthand to be able to use especially if we're working with
04:37numbers like 1-5000.
04:38but that's really all there is to using ranges. You don't use them that much but
04:43when you do use them, they are really a critical tool to help you out.
Collapse this transcript
Constants
00:00In this movie, I want to talk about the Ruby object-type constants.
00:03Now we don't use constants very often in Ruby at all, but it still is helpful to
00:07understand them for couple of reasons, which we will see in a moment.
00:10It's fitting that we are going close out with them because constants work a
00:13lot like variables.
00:14They are not true objects in Ruby, they are a part of the language construct and
00:18they point the objects the same way that variables do.
00:21The difference is that a constant is constant.
00:24It should stay the same.
00:25A variable will change over time.
00:27So x=1, x+=1, now x=2. It's variable.
00:33A constant should stay the same.
00:35Only in Ruby, it's not necessarily the case. Let's see.
00:38We will open up irb.
00:39We have already seen the way that we specify a variable name like test = 1, right?
00:44That's a simple variable name.
00:46Well, the way we want to specify constant names is with all capitals.
00:50TEST equals, let's say, 2.
00:52Two different things to return two different values.
00:55The first is a variable, the second is a constant.
00:58Now there are couple of quirks with constants that it's important for you to
01:01know about and that's the main reason why I wanted to include it here.
01:04The first is that actually anything that begins with a capital letter at the
01:09beginning, it's like a variable, is considered a constant.
01:12So Hello equals, let's just say, 10 for now.
01:15Okay, that is actually going to be a constant and we'll see how we can tell the
01:20difference in one moment.
01:21The second quirk is that, of course, if we change a variable, test = 100, no problem.
01:27But TEST = 100 comes back and gives us a warning and says you've already
01:32initialized the constant TEST.
01:35Because this is a constant,
01:36it did not want to let us do that, but it did do it.
01:42It is not truly constant.
01:43It did go ahead, even though it raised this warning to us, letting us know that we
01:46shouldn't be doing this, it went ahead and did it and the same thing is true
01:50with Hello = 20, let's say. Same thing.
01:54It's a constant, and that's how we can tell that it's a constant.
01:56So those are the two quirks that I want to make sure I highlight to you.
01:59These kinds of quirks are totally the kind of thing that I can see changing in
02:02future versions of Ruby.
02:04In fact, your version that you're using may handle this different already.
02:08Because there is a little bit of quirky behavior, this is the kind of thing that
02:11you could totally see changing in future versions of Ruby.
02:14So if yours doesn't give the same response as this, don't worry about it.
02:17Just notice what it does do.
02:20Most importantly what I want to make sure is that you saw that this is the way
02:22to name your variables, not using these capital letters, because in that case,
02:26it will consider a constant.
02:28So you do want to always use all lower case for your variable names and that's
02:32really all there is to working with constants.
Collapse this transcript
3. Control Structures
Conditionals: if, else, elsif
00:00In this chapter, we are going to be talking about the control structures inside Ruby.
00:04In the previous chapter, we were talking about a lot of the basic object types,
00:07but we really don't get that far if we are just assigning different
00:10objects to variables.
00:11Control structures are really going to provide the action that happens inside
00:15of our Ruby programs.
00:17It's what's going to decide what takes place under certain circumstances
00:21and the first way that we are going to determine those circumstances is
00:24using conditionals.
00:25So this is, if something is true, we are going to do one thing.
00:29If it's not true, do something else.
00:31Right, that's the basic thing.
00:32We will run one set of code under one condition, another under
00:35different conditions.
00:36That's why they are called conditionals.
00:38To do that, we are going to use the syntax of conditionals, which is going to be
00:42if and then a boolean expression and then end at the end and then in between
00:47will be the code that we want to take place if that Boolean value evaluates to true.
00:51So if x is equal to 1 then do this bit of code.
00:54Otherwise don't bother, just skip right past it.
00:57That's how conditionals will work.
00:59Now, we could write two conditionals.
01:01We could have if x is equal to 1, then do this.
01:04If x is not equal to 1 then do that.
01:07But because that happens so common we have if and else that we can use.
01:12So if x is equal to 1, do something, else do the alternative.
01:17Right, it allows us just to branch it in two simple directions based on the
01:20true/false value of that first conditional.
01:22But what if we want in branch in more than one direction.
01:25We don't want to just have a yes or no action.
01:27We want to have more complicated choices.
01:30Well, we have another option for that which is elsif and that's not a typo.
01:34It is e-l-s-i-f and that allows us to do another test before we get to else.
01:39So if x is equal to 1, do something, elsif and let's say x equals to 2, then do something else.
01:47But if neither of those is true, then do this default else action.
01:51That will be the fallback choice
01:52So be careful that you spell elsif correctly.
01:54That does trip up a lot of beginners, especially because other programming
01:57languages do it differently.
01:59So an actual conditional statement might look something like this: if x < 10
02:03puts "Below 10"elsif x > 20 puts "Over 20"else
02:09puts "10-20" and then end.
02:12Now notice that we don't have any parenthesis or curly braces or anything like that,
02:17letting it know where each of these sections is.
02:19Different languages handle that differently and a lot of them require you to put
02:22either parenthesis or curly braces. Ruby does not.
02:25It's one of the nice things we can just leave them out. The Ruby interpreter
02:28knows that when we start a new line, we are ready to start the code in that
02:32if statement and it will just keep parsing away until it gets to either
02:36elsif, else, or end.
02:38And when it gets to one of those, it knows that those are magic keywords
02:41that ought to tell it to stop that block of code and now do another part of the conditional.
02:46Now the tabs that are in there, where I have it intended for each put statement,
02:50do not signify anything to Ruby.
02:52It doesn't use those at all.
02:53They are only there for our readability, so that we easily see what's being
02:57executed between each of these parts of the conditional. Let's try one out.
03:01So we are just going to irb and instead of using just x, let's say name =
03:07"Kevin". That will be my assignment.
03:08So now the variable name, so we say if name == to "Bob" and again the
03:17indentation doesn't make a difference, but we go ahead and do it, puts and let's
03:21say "Found Bob" else puts "Not Bob...". There we go.
03:29So it was Not Bob.
03:31Now if we did the same thing, let's hit the Up arrow and ask it, if name equals
03:36Kevin then let's put "Found Kevin!" else puts "Not Kevin...".
03:47And let's type the end.
03:50So there it is, Found Kevin!
03:51So you see it does match.
03:53And elsif works the same way.
03:55You can say if name equals to Bob again, puts "Found him" and then elsif without
04:05the e, name equals Mary puts "Found her", else puts "Not Bob or Mary".
04:18Now I know that this seems like a lot of typing,. We have never used the Up arrows
04:21to back and reenter old lines.
04:23It a little bit cumbersome to do it this way.
04:25You can put all of this into a separate text file and then just copy and paste
04:30into irb each time and then when you paste in, it will execute the code.
04:34So that's a nice way to do it.
04:35It save yourselves typing if you're trying to work out a particular problem.
04:39Now notice that throughout this I did not use parenthesis or curly braces to
04:43tell Ruby where the blocks of code are.
04:46Other languages do that.
04:47They require you to use curly braces and parenthesis in different places.
04:51You don't have to do that here.
04:52The Ruby interpreter knows that when you go to a new line after an if
04:55statement, that we are now in that if block of code and it will keep going until
04:59it gets to elsif, else or end.
05:01That's a conditional keyword, so now I know that I'm ready to do whatever that
05:05next conditional instruction is.
05:07So it's nice that we don't have to type any of those or make sure that we've
05:10closed each and everyone that we've opened and so on.
05:12Now Ruby also has a very nice feature where we can put conditionals in line.
05:18What I mean by that is I can say puts "This is Kevin" if name == "Kevin", all right.
05:27I have the statement I want and then a space if the Boolean.
05:32So we can put it at the end and it knows because it was preceded by a statement,
05:36it's the statement that is only conditionally executed and that has the same effect.
05:40Now, let's just try if this name is equal to something it's not and now you see
05:45that it doesn't do the put statement.
05:47So that's a nice handy thing you have to do, so we don't always have to write
05:50three lines of code, if name = "Kevin" puts "This is Kevin" end, right.
05:55That's different lines.
05:57Instead, we can just put it all in one line nice and quick.
06:00There is a few more things I want to show you about conditionals.
06:02We will do that in the next.
Collapse this transcript
Conditionals: unless, case
00:00We have gone over all the basics that you will need in order to work with
00:03Conditionals, if, else and else if will do everything that you need.
00:07However, there are a couple of convenience conditionals that we can also use
00:11that work kind of like a shorthand.
00:12We are going to look at four of them.
00:13There is unless, case, the ternary operator and or/or-equals.
00:19So let's start out by looking at unless.
00:21It looks like this, exactly like the if statement, but instead of if it's unless.
00:25So unless a Boolean is true, which means the same as if not true, it's the reverse.
00:32So instead of being if not x > 3, it's unless x > 3.
00:39So unless it's true, do this block of code.
00:42Now unless can sometimes tie you in logical knots trying to work through exactly
00:46when it's going to be used.
00:47So only use it if it makes a lot of sense.
00:50If it feels right and it's convenient use unless, but don't let it drive you crazy.
00:54You can always just switch back to if and then the exclamation point for not and
00:59it's the same thing.
01:00Now you can use else and elseif still with unless, but there is no such thing as unlessif.
01:05That doesn't exist.
01:07Unless often works best in really simple cases.
01:09When you start getting really complex, if is the better way to go.
01:12Now we saw how we could have multi- layered conditionals right, if something
01:17is true elseif something else is true, elseif something else is true and we could keep going.
01:21When we start to have a lot of these the thing that ends up being better to use
01:24as a shorthand is the case operator.
01:27So we basically say let's look at a set of cases when something is true, do this.
01:32When something else is true, do that.
01:34It's the exact same thing as the if statements. We have just rewritten it as the
01:39case operator instead.
01:40Now this might not seem like it's any shorter than what we had before.
01:43It's actually more lines of code to do the same thing, where it really starts to
01:48pay dividends though is when there is a real parallel sort of assignment where
01:51we can say okay, when x = 1 do this, when x = 2 do that, when x = 3 do that and
01:57so on, and it's just right down the line in each of these specific cases.
02:01Now because that's when case works best is when we are comparing a test value
02:07against a given value.
02:09There is also another way to use case, which I think is probably even more often
02:13used, which is to put the test value right after case.
02:17So case and then x, let's say. When 1, do a block of code.
02:23When 2, do a block of code.
02:25So this really is more of a shorthand and really saves you from having to
02:28write x == 1, x == 2 each time, we just say x when it's 1, when it's 2, when it's 3 and so on.
02:36And we can have the else statement there at the end or we could leave that off, if we want.
02:39Now in some other programming language this kind of structure is called switch.
02:43So if you've been using that, you will want to switch over to start using case
02:47instead, because that's what it's going to be in Ruby.
02:49The next one I want to show you is the Ternary operator and what this is it's a
02:53shortcut for simple if and else statement.
02:56So if something is true, do one thing, else do something else.
03:01Well, in the case when those are really short, especially the blocks of code,
03:04it's just one very quick little bit of code that we want to write.
03:07Writing those five lines takes up a lot of space and we can do a lot faster if
03:12we just do it with the ternary operator, Boolean space question mark.
03:17Make sure you have the space there and then a question mark, and then whatever
03:20little tiny bit of code we want to run.
03:22You don't want to run a whole lot of stuff in here.
03:24That's not what this is for.
03:25This is only when we are just going to do something real quick and we want a
03:28very quick conditional.
03:30If that's not true, the else is the colon.
03:32So space colon space and then the second bit of code we want to do.
03:36So as an example, we can have puts x == 1 and then it will either return 1 or
03:43not 1 and that's what we will get output, depending on the Boolean x = 1.
03:46Now this is not highly readable code like a lot of Ruby is.
03:51So you really want be careful about using it and use it only in those cases when
03:55we are just going to do something very small.
03:57But in those kind cases it can be a real lifesaver and save you a lot of typing.
04:01The last one that I want us to look at is the or and or/or-equals operator.
04:06Imagine that we have the simple case where we want to say if y has a
04:09value, then set x to it, but if not, go to z, which is like a default value, a fallback.
04:16So if you have y set it to y. If not, fall back to something else.
04:20Well, we can use the Or operator for that and we could use it like this. x = y or z.
04:24So if y doesn't exist, then it will be z.
04:29Now we use that in our Booleans remember as an or operator and you will remember
04:33that it evaluated the first part to see if it was true or not, and if not, then
04:37it went to see whether the second part was true or not.
04:39Well, that's essentially what this is doing.
04:41It's checking that first one. If it doesn't exist and doesn't have a value,
04:46then it's not true.
04:47So it goes to the next part and it does have a value the value z, so that's
04:51what it sets to x. So it's worked exactly like our Booleans do, but we can use it for assignment.
04:56So this is a real nice shorthand.
04:58It's a lot shorter than writing something like this.
05:01The other one that comes up a lot is we want to say unless x already has a value,
05:06set x = y. So if x has a value already, just leave it alone, don't set anything.
05:11But if not, we want to set it to y. Y is like a default value.
05:14Well, the notation for that is going to be x and then the or operator with the
05:19equals after it, the same way we had plus equals, minus equals and all those kinds
05:23of assignment operators. This is or equals.
05:26So if x has a value, we will leave it alone, but if not then we will set x = y,
05:32and I think that also is a lot shorter than writing something like this.
05:36So all four of these are really just shorthand methods that allow you to do
05:40things a little bit more efficiently.
05:42You could use if, else and elseif to accomplish the exact same thing in every case.
05:47Go back over it one more time to make sure you understand it.
05:50Go into irb, try all four of them out, get used to how they work, because they
05:54really are going to be big timesavers for you.
Collapse this transcript
Loops
00:00We continue our discussion of Ruby's control structures by taking a look at loops.
00:04Now a loop does exactly what you think it would.
00:07It loops through a bit of code over and over and over again until you tell it to stop.
00:11And the way that we define a loop in Ruby is by simply having loop space and
00:16then word do, then the code that we want to repeat will be on a new line after that
00:21and then on a new line once that's done, we would have the word end.
00:24Everything from do to end would called a code block and we are going to be
00:28talking more about code blocks a little later on and going into depth with them,
00:32because they're a really useful thing.
00:33This really the first time we've encountered them, so just make a mental note
00:36this is our first code block.
00:38Loop will take a code block and just loop through that block over and over and over again.
00:43In fact, if we were to go to irb and just type in something that was a really
00:47simple look like this, it would just keep looping and it's called an infinite loop,
00:51because it doesn't stop.
00:52It just loops till infinity.
00:54So we really need a way to have a control over our loop, because we don't
00:57want it to go forever, we just want it to repeat a few times until maybe a
01:00certain condition is met.
01:02So the controls we will use on loops are going to be break, next, redo, and retry.
01:08The most useful by far is going to be break and next and I am going to be
01:11focusing on those here.
01:12Break is where we will use to terminate the whole loop and that's what you'll
01:16use a lot, because you will basically use a conditional to say well, if x > 10,
01:21then break out of this loop.
01:22We are done, we are doing looping.
01:24The second of those commands, next, just says immediately jump to the next loop,
01:29start the loop over again, but don't do anything that's below me.
01:33Whereas break says quit immediately, next says loop immediately.
01:37Now redo redoes that same loop over again and retry starts the whole loop
01:43over from the beginning.
01:44It really is going to apply more to some more complex loops we will look at later on.
01:48So let's focus on break and next and try those out.
01:50So let's open up irb with a simple- prompt and let's start out by saying x = 0.
01:57Now we are going to do a loop, loop do, and in our loop we are going to want to
02:01say x is going to increment by 2.
02:05Now we will want to break out of our loop if x >= 20, but if it's not, then
02:12we are just going to output the value of x. So think about for a second what this
02:16is going to do and then go ahead and hit Return after end, and you will see that
02:20the loop starts. x = 0 at the very beginning.
02:24As soon as the loop starts, x becomes 2 which is still less than 20, so we
02:28don't break and then it outputs 2 and then it just loops through that over and
02:32over again incrementing x until x finally becomes 20 and then it breaks out of the loop.
02:38It never outputs the number 20, because it never gets that far.
02:41As soon as it gets to the break line, it breaks immediately and then we are out
02:44of our loop and our code is done and everything quits.
02:47Then let's try the same thing, but with next.
02:49Let's set x back = 0 again, because it's going to be equal to 20 at the end of that loop.
02:54So x = 0. Let's do loop and we will do the same thing x += 2, break also just so
03:02we don't have an infinite loop and have the same conditions, but now let's put
03:06in next if x = 6 and then we will still go ahead and output x at the end, puts x,
03:14and then finally end.
03:15So take a look and see what you think that'll do and then hit Return.
03:19So we got the same list except for the number 6 is missing.
03:222, 4 and then it jumped to 8.
03:25That's because when it went through the loop and x = 6 after it incremented,
03:29it got to the line and said next if x = 6 and it immediately started the loop over
03:34and it never got to that puts x statement.
03:36So therefore we ended up just skipping it.
03:38So that gives a good illustration I think of what next does.
03:41So let's take a look at some more complex loops.
03:44Specifically, I want to introduce you to while and until and these are basically
03:49loops that just have that Boolean break condition built into them.
03:53So the first one is while and then are Boolean condition, do our loop and then end.
03:58Now there is no do, notice that. That's little bit different. There is an implied
04:02code block there, but there is not the do end that we have when we have a loop.
04:06So while something is true, keep doing this loop.
04:10Now the reverse of that is until something is true.
04:14It works the same way as if and unless, you'll remember that unless is the
04:18same thing as if not.
04:19Well, until is while something is not true.
04:23But other than that it works exactly the same way, and which one you decide to
04:26use really just depends on what you are trying to accomplish and which one
04:29just feels more natural and fits with the English language syntax of what you are trying to do.
04:34So to give you the concrete example of how that while loop works,
04:37let's take another look at that loop that we just worked on an irb by using the while syntax.
04:42x = 0, while x > 20, x is going to increase by 2 and we are going to output x
04:49and then we will end.
04:51So what we have done is we have taken that break if statement and made it part
04:56of the loop structure itself.
04:57That's what our Boolean test up at the top.
05:00So let's try typing that in.
05:01Let's say x = 0 now while x > 20.
05:07Now notice I turned it around.
05:08Before we were working with x >= 20, now I am doing while it's < 20.
05:15Same thing just flipped around.
05:16So while x > 20, x += and then we will puts x and end.
05:23So all I have done is remove the break. I am not going to worry about the next
05:26for now. We are just looking at the simple example using break.
05:29So let's try it out look at the list that it gives you.
05:31Notice up here, the last number was 18 and that was true up here as well.
05:36Last number was 18.
05:38Now my last number is 20.
05:39So that's an important thing to notice about while loops.
05:42It matters with the value x is at the start of the loop.
05:46Before when we are doing our break, it mattered what was happening inside of the loop.
05:51We had the break after x incremented.
05:53It went ahead and looped anyway.
05:55Here it doesn't start the process, if this Boolean is true.
05:59So it's like evaluating at the very top.
06:01In fact, the equivalent loop statement would look like this.
06:05Now notice that what's different about this is that I've moved that break
06:08statement from below the x += to above it.
06:12That's what's different about it.
06:13So at the very top of the loop is the very first thing that gets evaluated.
06:16So just be careful about that when you're using while.
06:19Now while and until also work the way if does and we can use them inline.
06:23So for example, we could have x = 0 puts x +=, while x < 100.
06:32So we can just do it all in one simple line. If it is just a real simple
06:34statement that we want to repeat, this will work for us.
06:38Then I have given a second example here where I am using until. I have got y
06:40= 3245, then we simply puts y /= 2. Remember the divided by equal works the same ways =+ does.
06:50So y /= 2 until y >= 1.
06:54So it will just keep getting smaller and smaller and smaller, putting out the
06:56results until finally the value is <= 1.
06:59Now this is an interesting one for you to review some of the things that we
07:03talked about before, because the numbers that it outputs might not be the
07:06numbers that you would immediately expect unless you remember back to those
07:09pitfalls we have talked about.
07:11So that's really all there is to working with Ruby's loops.
07:13The loops are really primitive and really simple even when we're able to use the
07:17while and until forms. They are still very, very simple.
07:20The real power in Ruby is with another looping structure which are called
07:24iterators and it's very important that we look at that next.
Collapse this transcript
Iterators
00:00In this movie we are going to take a look at the Ruby Control Structure for iterators.
00:04Now iterators work a lot like loops which we just saw in the last movie.
00:07The difference is that instead of just looping, waiting for something to happen
00:11for us to take control and to either break out of it or to do something else,
00:15instead with an iterator we are going to traverse a fixed set of data.
00:19So we can kind of know where the starting point and the ending point is.
00:21We basically want to say for each one of these things do this process, do this loop, right.
00:28So we are going to do a code block once for each item in a set of data.
00:33Now we can accomplish that with loops.
00:34For example here is a While loop.
00:36Essentially what this while loop is doing is just outputting Hello five times.
00:41Before trying to do that, there is a simpler way to do it using the Ruby syntax,
00:45which is just to say 5.times do and then our code block.
00:50That's a lot easier. It is a lot cleaner.
00:51It is easier to see what we are trying to do and we have to write less code in the process.
00:56This is an iterator.
00:57Now it might not be obvious to you how this is iterating through numbers
01:01instead of looping.
01:02It may look like it's just looping five times.
01:04But it's actually not and we will see that in a moment.
01:06But first, let's take a look at some of the other iterators that are
01:09very similar to this.
01:101.upto (5) and that will put Hello;
01:145.downto (1) put Hello or we can use a range.
01:18(1..5).each put Hello.
01:21Now the last one probably makes it the clearest.
01:23What we are saying is take each item in this range and do this code block.
01:28Now notice I have curly braces around my code blocks now instead of the do end
01:32that we were looking at before.
01:34This is just the shorthand syntax for it.
01:36So you will be seeing both, both of them are code blocks.
01:38Again we will be talking about code blocks later on, but just make a little
01:41footnote, do end is a code block and the curly braces are code blocks.
01:45Same thing. I could have written it this way just as easily.
01:48Now there is more to an iterator than simply making it shorter and easier to write.
01:51There is actually a really nice thing where we have access to the values that
01:56are inside that data set while we are iterating through. Let me show you.
02:00So here is that same example.
02:02From 1.upto (5) do and now notice after the do I have a little something extra.
02:08I have an upright bar which we call a pipe, an i and another pipe.
02:11And then i can be anything. I could make it X, I could make it num.
02:15It is just a local variable that I am going to use inside my loop to keep track
02:20of the data that is in this data set.
02:22So the first time through i is going to be equal to 1.
02:25Second time through it will be equal to two.
02:27So it will increment. As we go through it will grab that next value of i.
02:32Now you can see that I am actually outputting that there, puts Hello + and then I
02:37will take the value of i to strings so we can actually see it.
02:39I am going to open up irb with simple prompt.
02:42Let's go ahead and create that same one. 1.upto(5) and then do and we have the
02:49upright bar pipe, right followed by an i. I am going to go ahead and use
02:52something different now so you can see that can be anything, num for example,
02:56a new line and now it's my code block.
02:58It is a code block where I have num available to me and num is the value of each
03:04element as it iterates through the dataset.
03:07So we can have puts and we will have Hello with a space +num.to_s.
03:14Just to go ahead and make sure because it will be a number because that's what
03:17we are iterating through, right?
03:18The numbers 1 to 5.
03:19And then let's end that and you will see what it outputs.
03:23Our iterator yields that value of each of those items as it goes through into
03:27num and we can output it.
03:29Let's try a different example that doesn't use numbers.
03:32So let's say we have fruits and in our fruits array we will put a banana and
03:37let's put an apple and how about a pear?
03:39So that's just a simple array of fruits.
03:43Well now I can say fruits.each do, so for each item there I am going to
03:49declare the value as fruit.
03:50Let's go ahead and make it something nice and common sense, right?
03:52It makes sense that each one as we go through is going to be a fruit.
03:55So as it iterates, it will pop a fruit into that value fruit and then I can say
04:00puts and let's say fruit and let's just capitalize.
04:06There we are, banana, apple and pear.
04:10So you can see, it went through each one.
04:12Now it also then gave me a return value back at the end.
04:15Don't worry about that.
04:16That's the return value for fruits.
04:18That's what it gives you back.
04:19What we are interested in is the output.
04:21What it actually did here where we went through our loop and we iterated along each item.
04:26Now there is another form to this each I just want to show you as well.
04:29Sometimes for beginners this is easy.
04:31We say for fruit in fruits, right.
04:36This is not the same as if we had a For statement in another language something
04:41like C++ or Java, PHP. They have different kinds of For statements.
04:47It is not the same at all.
04:48This is for each item and we are basically declaring a name here, same thing.
04:53These are equivalent.
04:55For each fruit in fruits output that fruit.
04:58So it's exactly the same thing just a different syntax of writing.
05:01If it is easier for you to remember this way, great.
05:04If you are totally hip with this code block thing and you are ready to do it,
05:07then go ahead and use this fruits.each do as a fruit and then execute whatever
05:13is in your code block.
05:14Now we still have access to those same control functions that we used with our loops.
05:19This work in iterators as well.
05:20Break, next, redo and retry.
05:23I am not going to show you how those work but redo and retry are little more
05:26useful in our iterators because now retry doesn't just say, "hey start a loop over."
05:31Retry says go back to the beginning of the set.
05:34So if we have banana and then we have apple and then we do a retry, well now
05:38it is going to jump back to banana again and retry starting from the beginning of the list.
05:42And if we have our redo, same thing if we went banana, apple, if we do a redo,
05:47it is going to the apple again.
05:48We will need of course to have some branching conditional If statements in there
05:52to make sure that we don't just endlessly loop on one thing.
05:55But we can use redo and retry a little more effectively with iterators than
05:59we could with loops.
06:00Now there a lot of different iterators in Ruby and I am not going to try to go
06:03through each of them with you, but you can look up the documentation on them.
06:06I want to just give you a list of what some of there are.
06:08So we have got with Integers and Floats, we saw how we could do times like 5 times 10 times.
06:13Upto, downto, there is also step and that step just basically says go from 1 to
06:1910, but we are going to step every 2 right, so that we could go 1, 3, 5, 7.
06:25Range we can use each for each other we saw. We also can use step there.
06:29So it will go from the beginning of the range to the end of the range by
06:31whatever step we tell it, every four numbers, every five numbers.
06:35With string we also have each.
06:37We have each line, we have each byte.
06:39With array we can use each, each index of the array or each item in the array
06:44with its index, in which case we actually get two values yielded up to the
06:48variables that we declare inside the pipes.
06:50So we actually put pipe and then one variable, and then another variable then
06:55the final pipe and we have two values we can work with.
06:57And then with the hash we have each key, each value or each pair which also
07:01yields up two values that we can work with.
07:03Now we will be working a lot with iterators and they will become
07:06very comfortable to you.
07:07I think you will also find that you use iterators many times more than you use loops.
07:12Iterators are going to be just much more useful for you and there is a lot more
07:15things that you can do with them.
07:16Now that we have talked about the control structure and we have touched on the
07:19way the code blocks can be useful for us, I want to spend a chapter talking
07:23in-depth about code blocks and the different methods that make use of them.
Collapse this transcript
4. Code Blocks
What is a code block?
00:00In this chapter we are going to take a closer look at Ruby's code blocks.
00:03We briefly touched on code blocks back when we working with loops and the iterators.
00:07But let's start out by looking at what is a code block and reminding ourselves.
00:11When we had an iterator like 5 times, we had a code block and the code block was
00:15a block of code that we wanted to be executed each time through the loop,
00:19each iteration and that block of code is defined between the do and the end.
00:24So everything between do and end is our code block. In this case it just simply puts Hello.
00:28Now do end is what we use for multiline code blocks.
00:31That's where it really is the most benefit because we can just keep putting lots
00:34and lots of lines in there.
00:35It could be a hundred lines of code that would be executed five times.
00:39Now if we have something that's so simple like puts Hello, then we saw that we
00:43can also use the shorthand notation which is just the curly braces.
00:46So 5.times puts Hello.
00:49If we have something that is that short this can be much more efficient,
00:51cleaner and easier to read.
00:53We also saw when working with iterators that during each iteration we can have
00:57the iterator yield the value up to a variable.
01:01In this case a variable that is declared between those upright pipes.
01:04So the variable i would be a block variable.
01:07And so each item in the dataset 1 to 5 would be yielded up to that variable so
01:12that that would be its value each time through and we would have access to that
01:15value then while we were inside our code block.
01:18So in our case we just puts Hello and then we used i after converting it to
01:22string just as output.
01:23But we could do anything with that value we wanted to and this block variable
01:27declaration that we did is not unique just for the do end syntax.
01:31We can also use it with that curly brace syntax just as easily.
01:34Let's switch over to irb and try it out.
01:36Let's open up another irb session with simple prompt so we get that out of the way
01:41and let's start by just creating an array and our array will be 1, 2, 3, 4
01:45and 5, nice and easy.
01:48So we saw we can use an iterator like each and then we can have a code block and
01:52I will use num as the variable that will be yielded up instead of i. We can name
01:56it anything we want, puts num * 20 and then we will close our code block.
02:02So it will iterate through the array each time the value 1 will go up to num,
02:07then number 2 and then 3, assigning it to that block variable which we can then
02:11use in our code block to multiply it by 20.
02:14Now before we knew about blocks we were using local variables, right?
02:17We were just simply typing a variable like x=1.
02:19That's a local variable.
02:21Local variables and our block variables are going to look very similar.
02:24Do you remember back to when we introduced variables in Chapter 2,
02:27remember that I gave you the naming conventions and local variables and block
02:31variables look the same.
02:32They don't have a $ sign or an @ sign in front to distinguish them.
02:36But the reason there are two different kinds of variables is because they have
02:38different variable scope.
02:40We touched on scope briefly but you will remember I said we didn't really have a
02:43way to talk about scope yet.
02:44Well now we have blocks we do have a way to start discovering what variable
02:48scope means and how it applies.
02:49So I have now gone through my iteration.
02:51I have declared a local variable array. I have declared a block variable num and
02:56I have declared a local variable x.
02:58Let's ask for the value of our block variable, puts num.
03:02You will notice that it comes back and it says that the variable num is
03:06undefined because it is looking for a local variable.
03:09That block variable exists only inside the block.
03:12So we only have access to it inside the block.
03:14And that's what we mean by variable scope. Because we have access to it inside the block,
03:19the block is its scope, right.
03:21We don't have access to it outside and what it really is doing is it is using
03:24num in the temporary sort of a way and then discarding it at the end because the
03:28block is done, so there is no reason for it to keep it around.
03:30Now that is variable scope at its simplest, but there's three important points
03:34that I need to make for you about scope.
03:36The first is that even though we don't have access to our block variables
03:39back in our local scope, we do have access to local variables inside the block's scope.
03:45So I am going to hit the up arrow until I go back to my iterator and I am just
03:49going to make a small change here.
03:50I am just going to put in a +x at the end.
03:53So we are calling now this x=1 that we have defined in the local scope.
03:58It doesn't exists in the block variables at all.
04:00So let's go ahead and hit Return and try it and you will see that it does still
04:03pull in the local variables into the block.
04:06So that's the first point.
04:07The second important point is sure to confuse some of you.
04:11Let's try doing a puts num again. num still is undefined. I have never
04:15defined in the local scope.
04:17So let's try it now.
04:18Let's say num=1 and let's try our example again.
04:22I will just hit the up arrow and we will run it.
04:24Now let's say puts num.
04:27Now some of you will have gotten the result of 5, just like I did.
04:30But I suspect that there are also some of you who have gotten the number 1 and
04:35if you did, just bear with me for a minute and we will get to explaining why.
04:39If you got the number 5 like I did what's happening is that Ruby is bringing in
04:44this local value for us to use inside the block. The same way that it brought in
04:48the local variable x, it brought in num.
04:50The fact that we declared it as a block variable Ruby didn't worry about. Ruby said, Oh num!
04:55Well I know there is already a num.
04:57I am going to bring that variable into scope.
05:00It is almost as if we had not declared it as a block at all.
05:03It is just making use of it the same way we can use x. That's what happened for me.
05:07Now for those of you who didn't get that result, who got the number 1 back,
05:11which means that it did not change its value, it was still num=1.
05:15That's because you are using a newer version of Ruby.
05:18With Ruby version 1.9, I think actually starting with 1.9.1, it behaves
05:23differently and if we declare this value here, it keeps it from bringing it into scope.
05:29It says no I really mean num ought to be a block variable.
05:34The fact that we have used x here still works just the same. It is bringing in
05:37the local scope variable.
05:39But the fact that we have declared it as a block variable makes it only be a
05:43block variable and that makes a little more sense.
05:45So I think that's going to be an improvement for the future, but it is a big
05:48change and it is a big change that's happening over the next couple of months.
05:51So this is coming soon.
05:52So you want to be aware of both cases so that if you are working with a version
05:56of Ruby that's before 1.9 that it will have the old behavior, if you have a
06:01version that's newer than 1.9 it will have the new behavior.
06:04And this difference in Ruby versions is the third point that I wanted to make
06:07you about scope inside blocks.
06:09Now if all of that was confusing to you and you just want to avoid the issue
06:12altogether, there is a very easy way to do it, which is just to name them
06:15different things, to name what's your local variable and your block variables
06:19different things and then you won't have that kind of conflict.
06:22And one good way to do that is to give your local variables long
06:24descriptive names like count=0,
06:28then inside your array use variables like num, i, x, a, b, c those kinds
06:35of things that are really short and sort of indicate that it is temporary in
06:39nature. We are just going to be using it inside the block.
06:41Now there are times when you are going to want to use things that are
06:43descriptive inside the block because you are going to be using it a lot.
06:46So it might be better to use something instead of just as a or b. But a lot of
06:49times having a real difference between the local variable names and the block
06:53variable names can really help make a good distinction for you.
06:56Now that you understand the basis of code blocks and we have gone over how
06:59block variable scope works, we are ready to take a look at some of the common
07:03Ruby methods that are going to make use of blocks, specifically find, merge,
07:08collect, sort and inject.
07:11Now there are by no means all of the Ruby methods that make use of blocks. There are a lot of them.
07:15But these of the most common ones and the ones that you will get the most use out of.
07:18And I think they also provide a good illustration of the different ways that
07:22blocks can come into play.
Collapse this transcript
Find
00:00In this movie we are going to see how we can use code blocks effectively with
00:03various Ruby Find methods that allow us to find objects inside a dataset.
00:08There are five main Find methods we will be looking at:
00:11find, which also is a synonym of detect, find all, which also has a synonym of
00:16select and then any?, all? and delete_if.
00:22Now delete_if may not technically fall under the umbrella of Find, but what
00:25we are really doing is finding something and then deleting it, all in one step.
00:29So I am going to go ahead and include it here.
00:31The thing that all of these methods will have in common is that they are going
00:33to take a code block and that code block for each and every one of them is going
00:37to be a Boolean expression.
00:40So code block does not necessarily have to be made up of sort of action
00:43statements, things like puts or setting variables and all sorts of processing.
00:47It can be a Boolean just as easily.
00:49I think it will make a lot of sense once we try it.
00:51Let's start by open up irb with a simple prompt and let's start out by using a range,
00:57remember we talked about ranges before.
00:59A range 1..10 inclusive and let's apply the find method to it.
01:04Now we are going to need to have a code block after that.
01:05We know a code block is going to be the curly braces for a simple one line code block
01:09and I am also going to put the upright pipes and declare a block variable of i.
01:13So each number in the range will get put into i as it iterates through the set.
01:19Now it's not actually an iterator but it does work according to the same principles.
01:23It is going to take each value and present it up to that block variable.
01:26So now we need to write a Boolean expression here.
01:29We could just write something simple like i =5 and then when we return it,
01:35you'll see that it comes back and it says ah, 5.
01:38It went through the set and it went until it found the item where i was equal to 5.
01:42Now that's kind of an obvious thing but we could have been checking for
01:45something much more complex and we might not have been using just numbers in a range.
01:48We could have be using something like an array of complex objects, where
01:52we were checking various things as we went through to see if they match.
01:55But let's give another example which I think will illustrate it a little better.
01:58Let's erase this and instead let's use the modulo operator.
02:02Now if you are not familiar with this from other programming languages--
02:04we haven't talked it about yet.
02:05What it does is it divides i by 3 and returns the remainder, whatever is left over.
02:11And so if it divides evenly the remainder should be 0.
02:14So what we are asking for is what numbers are evenly divisible by 3.
02:19So let's run that and you will see that it comes back with the first one, which is three.
02:24Now there are other ones that it could have returned but it doesn't do that.
02:27It just returns the first one and that's why find has this synonym of being detect.
02:34So start looking at this set and detect the first one, so that works the exact same way.
02:38Let's try detect again, but instead this time let's find out what numbers when
02:42multiplied by 3 are still between 1 and 10.
02:46So I will have another range, 1 to 10, and we can use include, remember we worked
02:51with that earlier, is include in that set i*3.
02:54So if we multiply 5 by 3 is it still included in this set?
02:58It came back and reported 1, because 1 times 3 is still in that set.
03:03It found the first one where that applied.
03:06Now what if we don't want to just find the first one? What if we want to find all?
03:09So find and detect will always either return a single object or they will return
03:14nil if nothing is there.
03:15We can try that real fast.
03:17Let's say detect the number 20 and there and it comes back and says no.
03:20So it is always either an object or nil.
03:23Now what if we want to find all? Let's go up here.
03:26Let's try our modulo again and this time let's just say find all for everything
03:32that's divisible by 3.
03:32You will that it comes back this time with an array, an array of the numbers
03:37which are divisible by 3.
03:38And if there had been none there, let's say numbers which are divisible by 30
03:43and there is none of them so it gives us back an empty array.
03:46So as I mention when we are listing them out, find all also has a synonym which is select.
03:51Let's try a select.
03:53Let's try it with this one here.
03:54So let's find everything where this is true and that's going to be select.
03:59So now 1, 2 and 3, all can be multiplied by 3 and still will not exceed the number 10.
04:06The number 4 when multiplied by 3 will be 12 so it I outside that range.
04:09We can also use Any and All in a very similar way.
04:12Let me just go back up here where we have the divisible by 3 and instead of
04:16using the Find All method we can use any?
04:19So are there any in this set where this is true?
04:22Don't return the value to us.
04:24Return a Boolean, True or False, right.
04:27So we are using a Boolean inside the block and we are going to return a Boolean
04:31as well and it returns the Boolean True.
04:33So it is true. There are numbers divisible evenly by 3 in our set.
04:38We can do the same thing with all and of course that will tell us well, are all
04:42of them meeting this requirement?
04:44And the answer is no, they don't.
04:46Now delete_if is not going to work with a range. Let's try it real quick.
04:49Let's delete_if, if it is evenly divisible, delete_if, there we go.
04:55So it comes back and it says, "sorry, a range you can't apply delete_if to."
04:59But if you remember, know how to turn our range into an array, you just put
05:04the square brackets around and instead and the asterisk, the splat operator, to expand it.
05:10All right so and now look what it gave us back.
05:13It is 1, 2, 4, 5, 7, 8 and 10.
05:17It left out 3, 6 and 9.
05:18So it is the exact same thing as doing a find all for 3, 6 and 9, but then it
05:24also does the extra step of removing them from the original array.
05:28So it is not technically a find, but because it works on the same principles
05:31I think it is useful to see it here.
05:32Now just because I am using ranges and arrays of very simple numbers to
05:37illustrate the point, doesn't mean you can't use more complex things.
05:40You can detect whether a string matches or not; you can see whether a hash has a
05:45certain value in it.
05:46Really any Boolean or almost any set of objects that you have where you can go
05:50through the set looking for something, you can apply these same methods to it.
05:54So just remember when you are using them that Find and Detect will return an
05:58object or they will return nil.
06:00Find All and Select will return an array of things that it finds that match.
06:04Any will be a Boolean. Either there are some in there or they are not.
06:08All would be like any except they all must meet that requirement of our Boolean test
06:13and they will return a Boolean True or False and delete_if will return an
06:17array with the items removed.
Collapse this transcript
Merge
00:00In this movie, we are going to take a look at another Ruby method that's going
00:03to make good use of code blocks, and that's Merge.
00:06And Merge is going to be used for merging hashes together, and it's for hashes only.
00:10This is not for arrays, or for ranges or strings or anything else.
00:14This is just a method that we are going to use with hashes.
00:16So let's open up irb with a simple prompt, and let's start out by just declaring a hash.
00:22I am just going to call it h1, real simple. h1 is going to be equal to a, which
00:28will point to the number 111, and let's have b, which will point to the number
00:34222 and that's our first hash.
00:37Now, let's make a second hash, h2, and in that hash, we are going to have b as a
00:42key for the value 333.
00:46And let's have c as a value for 444.
00:48Now, you can put in just about anything you want here.
00:51The important thing about the two is that you'll notice that b is a key in both
00:55of the hashes, and that's because I want to show you what happens when we merge
00:58them together in that case.
01:00So all we need to do to merge the two hashes together is h1.merge(h2) and it
01:07returns a merge hash.
01:09It takes the two and smashes them together.
01:11And if they are conflicting keys, the values that are in h2 are the values that
01:16are going to win out.
01:17That's what we are going to have.
01:17So you see we end up with 333, not 222.
01:20If we'd merged it the other way around, you'll see that we would have ended up with 222.
01:24All I did was switch which one was being merged into the other one.
01:28So this is just a real simple merge between hashes.
01:31It doesn't make use of a code block and that's what I really want to illustrate here.
01:35Now, this is just a very simple Ruby merge.
01:38We are not using a code block yet, and that's what we really want to see is how
01:41to make use of a code block.
01:42Well, we can also supply code block optionally if we want.
01:46So I am just going to hit the Up Arrow to get back to this h1.merge(h2).
01:50Now, the block in the case of merge is only going to be called when there's a
01:54conflict between two keys.
01:56So when it's merging together, it has no problems merging the A and the C keys together.
02:01You can easily just put those in there and there is no conflict.
02:03But what we are going to use is this block, it's going to be for
02:05conflict resolution.
02:07So we'll supply the block, and we are going to need to declare some values here.
02:11Now, we can call these block variables anything we want, but there are three
02:15values that are going to be yielded up to us by Merge.
02:18So it makes a lot of sense to name them something that indicates what their purpose is.
02:23The first one is the key, the conflicting key.
02:25The second one is going to be the old value, the one that's in the h1 in
02:30our case, and the third one will be the new value, the one that's about to be overwritten.
02:35Now if I simply put a New here as the way to resolve this, I'll hit Return and
02:42you'll see that we get the same behavior that we got up above.
02:45If I go back, and I change it to now be Old, you'll see that now we get
02:50the other behavior.
02:51It kept the old value.
02:53The final value that we return out of the block ought to be whatever we want
02:57the new value to be.
02:59So the block essentially says hey, instead of me automatically deciding which
03:02one wins out, let me pass you those variables and you decide.
03:07And at the end, what I need you to give me back is the correct value.
03:11Now, we can put something very complicated in here, but ultimately what we need
03:14to come up with is the value that ought to went out between these two.
03:18Now, if we did something like old times 2, you'll see that it did that for us. old times 5.
03:25Essentially, all we are saying is Merge, here's what I want you to do when
03:29you find a conflict.
03:31So as another example let's have h1.merge do and let's go ahead and do our key,
03:39old, and new, just so we can keep those straight, and now let's do if old is
03:45less than new, then keep the old one, else, return the new one.
03:53So do you see what we are doing?
03:54We are saying when there's a conflict, pick the one that has the lower value.
03:57I don't care which one is older or newer necessarily or which one it came from.
04:02I want to make sure that I end up with the lowest value, and you'll see that it picked 222.
04:06Now this is a little bit of a clunky way to write it.
04:08Actually, you probably would want to write it using something more
04:11efficient like merge(h2).
04:13We'll use our in-line notation, and I can just say K, O, N.
04:19And that's going to indicate to me which one is the key, the old value, and
04:21the new, old, less than N, then return O, otherwise return N, and that's using
04:28that ternary operator notation that we learned back when we were doing our conditionals.
04:32So that's a nice shorthand for us.
04:33It does the exact same thing, all in one line instead of being spread
04:36across several lines.
04:38The last thing that I want to show you about Merge is you'll notice that merge
04:40did not change my original values that I started with.
04:43Let's go back to one of our merges that doesn't have a block to it.
04:47Here we are, h1.merge(h2).
04:49If I put an exclamation point after merge.
04:52Now, h1 has been changed. h2 is still the same, but h1 has the bang at the end
04:59with the exclamation point.
05:00So it has said permanently change this one.
05:03This is a common theme we'll see in Ruby where this exclamation point gives us
05:07sort of a different version of something or maybe a supercharged version, in this
05:11case something that makes the change permanent.
05:13And just like the regular version of Merge, we can also supply a block to this
05:17version that has the exclamation point.
Collapse this transcript
Collect
00:00In this movie we are going to be taking a look at Ruby's Collect method, which
00:03also makes use of a code block.
00:05Collect has a synonym which is Map.
00:07It's really up to you as to which one you use.
00:09Sometimes I use map just when I am trying to conserve space, maybe keep it from
00:13wrapping around the line or something like that, or maybe I am feeling lazy.
00:16The Collect and Map are completely synonymous.
00:18We can use either one, so use the one that feels most comfortable to you.
00:21The Collect or Map method is going to really work the best with arrays,
00:25hashes, and ranges.
00:27An array is really the object that you will use it most often with, but hashes
00:31and ranges also work.
00:32So I'll open up a new irb session, simple prompt.
00:37Now, let's create ourselves an array to start with.
00:39So array = 1, 2, 3, 4, 5, nice, simple array. array.collect and then our code block.
00:48We are going to have a block variable declared.
00:50Let's call it i for now.
00:52So what Collect does is it iterates through the array, taking each item and
00:58passing it up to i, then does whatever we tell it to do in our code block,
01:04applies that processing to it, and puts that value into a new array.
01:09Let's try it just to see. Let's say i+1.
01:12That will be nice and easy to see.
01:14You'll see what it does.
01:16It took every item, and it applied this processing to it, and returned a new
01:21array with that processing applied.
01:23I think that's a really good way to think about it, is to think of that block as
01:26being whatever processing you want done to each element.
01:30So let's try it again.
01:32Instead of +1, let's do times 40.
01:35You'll see that we get 40, 80, 120, 160, and 200 out of that.
01:39We could do the same thing if we had something like apple, banana, and orange.
01:45So it's just another simple one.
01:47Let's use Map this time, and we'll take each fruit as it comes up and that's
01:52what we'll call it, fruit. capitalize. So there we are.
01:59We capitalized each one as it went through and it made a new array for us out of it.
02:03Now let's try something else.
02:05Let's say fruit capitalize if fruit = banana.
02:12That wraps around there, but you see what I did.
02:14I am saying capitalize it, if the fruit equals banana.
02:16Now notice when I get back here.
02:18I did not get apple, and orange back.
02:22I just got nil banana and nil.
02:24This is a very important point that throws off a lot of people about
02:28using Collect and Map.
02:29What happens here is if fruit is equal to banana, then it capitalizes it.
02:33Here it's returning the value of fruit capitalized, but if not,
02:38it's returning no value at all.
02:40Now, we can have something that works that way.
02:42We can say let's just erase this real quick.
02:45So I have do and then fruit, and then we'll start a new line, and now we'll
02:50write if fruit = banana, then return the value fruit.capitalize, else, return fruit.
03:04Now it will do what we expect.
03:06The important thing is that we do need to return some value out of it.
03:10So an if statement like this is not going to say apply this change only if it's true,
03:15 and otherwise return the regular value.
03:17We need to be explicit about that and say return that value.
03:21So whatever comes out of our processing, whatever value results from it, is
03:24what's going to get put in our array.
03:26So the value of processing fruit. capitalize if fruit equals banana, when it was
03:30apple, well it was not equal to banana, so nil was the result.
03:36So it put nil in there.
03:37Now why didn't it just return an array of banana only?
03:40That's a very important point that I want to make that I think will really help
03:43you out when working with collected map.
03:45You want to always keep in mind that the number of items that go into this
03:50Collect is going to be equal to the same number of items that come out.
03:54So if we take 10 things, we do processing on them, it's going to result in 10 more things.
03:59Now there may be some nils in some of those spots, but there are always be 10 items back out.
04:04So number of items in equals the number of items out.
04:07The other thing that you need to remember about Collect is that even though it
04:11works with arrays, hashes, and ranges, it always returns an array. So let's try that.
04:171 to 20 has arrange.
04:19Let's do Collect and for each one we'll call it num and num times 20. So there it goes.
04:27It returns each one multiplied by 20, but it turned it into an array at the same time.
04:32So that's the second thing that you don't want to throw you off.
04:34You might think oh, I have a range, I am expecting to get a range back or something.
04:38No, it doesn't work that way, and the same thing with the hash.
04:40Hash equals let's make a real simple hash here, A 111, and B is going to be 222
04:50and the key C will point to 333.
04:55Now, if we say hash.map, now with hash, we get two things rendered up to us.
05:01We get both the key and the value. K, V is a common way to write that instead of
05:06writing out key value.
05:07Then we can decide what we want to do with that key and value.
05:10So I can say well, take each one and return the key.
05:14I get an array back of all the keys.
05:16It's the same thing as if we ask the hash for its keys, hash.keys.
05:20We could do the same thing with the value, or we could say something like value
05:24times 20, and it returns an array again, taking each of those values and
05:28multiplying it by 20, or we could do something crazy like this.
05:31Let's say a string with the key in it, followed by colon, and then let's go
05:39ahead and put the value right after it. There we go.
05:43And then close our string.
05:44So there we go, we get a set of strings with the key value pairs with
05:48colons between them.
05:49It's still always an array that returns back, three items in equals three items out.
05:54If we try and put any kind conditional in there, we really need to make sure
05:58that we always get some kind of useful value unless we are okay with having
06:03nil values returned.
06:04There is one final pitfall that I want to show you with Collect.
06:07Let's go back up to where we had our apples and bananas example.
06:10So here we are with the simple version of it.
06:13We are just capitalizing all the fruit, just to remind ourselves that's what it does.
06:17Let's put Puts in here.
06:19So puts fruit.capitalize.
06:21So we did do the Puts, apple, banana, and orange, but look what the return value was?
06:27Nil, nil, nil, and that's because whenever we do a puts, right?
06:31Puts 1,2,3, the return value is nil.
06:35So if you put a Put statement inside there, you're going to end up with an array
06:39that is filled with nils.
06:41So if you are trying to for example take that whole thing, and you try to say ah!
06:45Well let's set that equal to something.
06:47Let's say new array equals.
06:51Now, if I say well what is the value of new array, because like I said it's
06:55equal to nil, nil, nil.
06:56It did not put those values in there.
06:58The right way to get them in there would be not to put the Puts in there,
07:02but just report the value back, and now a new array is equal to what we would expect.
07:06Just like we saw when we were working with Merge, Collect and Map had
07:10exclamation point versions that we can also use.
07:12Just put an exclamation point at the end and it will transform the array that
07:15we are working with
07:16so that the processing is applied in place, and it actually replaces the values,
07:21instead of giving you a new array.
07:23Collect and Map are really a powerful way to take an array and apply a
07:26transformation to all the elements in the array.
07:28That can be a really useful thing for you, when you are trying to do data processing.
07:32We want to take every item and just apply that same transformation for it.
07:35Just make sure that you keep in mind all the pitfalls I have shown you here, and
07:38I think you'll find it to be really useful.
Collapse this transcript
Sort
00:00In this movie we are going to look at Ruby's Sort method which also makes use of a code block.
00:04Now the code blocks we have been looking at before we've put Booleans in our
00:08code block or we've put conditional statements that determined whether or not a
00:12certain value should be returned, or we've returned a value as the result of
00:16some sort of transformation or processing that we have done.
00:18Well, the Sort, we are going to provide a comparison.
00:21We haven't really talked about comparisons yet, so let's look for a moment at
00:24the Comparison operator.
00:25Now, I also call this the spaceship operator, because that's what it looks like,
00:28a little flying saucer.
00:30So we have the less than sign, the equal than sign, and then the greater than sign,
00:34and altogether that makes up the Comparison operator.
00:38The way we use it is to compare two values.
00:40Value one on one side, value two on the other.
00:43When it compares those, the same way that a boolean compares two values and
00:46returns true or false, Comparison operator is going to do more than just
00:50check true or false.
00:51It's going to return -1 if one thing is less than the other, 0 if
00:56they're the same, or return the value of 1 if value one is more than value two.
01:02So Comparison operators are going to be really useful in sorting, but we can
01:05even use them just directly in irb.
01:07Let's open up a new irb session with simple prompt and let's just try 1 and then
01:12our space ship operator or comparison operator with 2. It returns -1.
01:16Let's try it again, just flipping around.
01:19It returns 1 to us, and then let's try it 2 spaceship operator 2. So now it's 0.
01:25That illustrates very clearly what's going on here with the spaceship operator.
01:30Now how would we apply it to sorting?
01:32When we use Sort, it's going to use the Comparison operator to decide which
01:36direction the two values ought to go in the sort.
01:39So if it's -1, in other words value one is less than value two, value one
01:44should be on the left. It will move left.
01:47Now obviously we are not talking about literal left here.
01:50We are talking about being less than when we have an ordered set.
01:54It's easy sometimes to visualize it as being left.
01:57If they're the same, well then they are the same.
01:58It doesn't matter which one comes first. They're identical.
02:01So we can just leave them wherever they are.
02:03If it returns 1 though, meaning that value one is more than value two,
02:07value one will move right to swap places essentially.
02:10Value one is a bigger number, so it will move off to the right.
02:13I think it's going to make a lot of sense when we try it.
02:16Let's start by giving ourselves an array that's out of order.
02:18So array equals, and I am just going to use 3, 1, 5, 2, 4.
02:25That's all jumbled up.
02:26That's our array, and an array is always going to be maintained in order.
02:30That's the nature of an array, is that it's an ordered set.
02:32So it will always be in that order, until we perform our sort on it.
02:35So array.sort and then we are going to need our code block.
02:40And the code block is going to have a couple of things declared as block variables.
02:44The first is going to be value 1, and the second is value 2.
02:48That's what we will use to compare.
02:50The Sort method will send each of these values up to us in turn for the comparison.
02:56So we can say V1 and then our comparison operator V2, you could write up value1,
03:02value2 or item1, item2, but the numbers 1 and 2 are very helpful to let you know
03:08that we are comparing the two.
03:09So what's happening in essence is that it's yielding up the first two values, 3 and 1.
03:14When those values come up to the sort block, it says oh!
03:17when I do my comparison, 3 is greater than 1.
03:21It returns the value of 1 from the comparison.
03:24Therefore 3 should move to the right.
03:271 will move to the left, but 3 is going to move to the right, and that will put
03:31them closer to the correct sort order.
03:33Now Ruby is not actually progressing through each and every one of those pairs.
03:37It has a more efficient algorithm that it can take advantage of to do it faster.
03:40But this describes the behavior of what's happening.
03:43So let's go ahead and try it and you'll see that sure enough it does sort them
03:47into 1,2,3,4,5. You may have already realized that we could do array.sort by
03:52itself, with no block and get the exact same result.
03:55That's the default behavior of sorting.
03:57The reason that we use the block is so that we can put more complexity to it and
04:00change the behavior.
04:02Let's say for example we wanted to reverse sort them.
04:04We could do that just by changing them and saying well, now if value 2 is
04:09greater than 1, or value 2 is less than 1, do that comparison instead, and that
04:13will reverse sort them.
04:14We also have a convenience method for that.
04:16I don't want you to feel like you have to go to that trouble all the time.
04:20array.sort.reverse will return the exact same thing.
04:23So what do I mean by having more complexity then?
04:25Well numbers aren't maybe the best way to see that.
04:28Let's try some strings.
04:30Let's go back to our fruits that we were working with earlier, fruits.
04:33Let's make banana and an apple, and an orange and a pear.
04:40So those all have different length names.
04:42We will go ahead and make that our array.
04:44Now if we just say fruits.sort, it's going to sort them in alphabetical order.
04:49That's the default behavior of Sort when it's applied to strings.
04:53It's going to compare them, and say ah, I am comparing two strings.
04:55I am going to sort them just simply based on this same V1, V2 comparison that we did up here.
05:01Well, what if we want something more complex?
05:03So for example let's say that we wanted to sort them by the length of the string.
05:07Not by alphabetical order but how long the string is.
05:10So fruits.sort, let's call the first one fruit1, and fruit2.
05:18So each pair of fruits will be passed up to it and we'll compare them saying
05:22fruit1.length when compared to fruit2's length.
05:27So you can see that it puts pear at the beginning because it's the shortest
05:31string, and banana at the end because it's the longest string.
05:34We could reverse the order of that if we wanted to, just by switching fruit1 and
05:38fruit2 or we can sort it the first way we did it, and then just apply that
05:42.reverse at the end.
05:43Now there is an easier way.
05:45If we know that we are just going to sort it according to one simple property
05:48like that, we can say fruits.sort by, and then we would have just one value that
05:55is going to be yielded up to our block variables, and we just need one fruit,
05:59and then we can say fruit.length. There we go.
06:02So now we get the same effect, just by using sort_by allows us to do it a little faster.
06:08Now essentially what sort_by is doing is it's saying go to the blocking get the
06:12value I should use for a comparison.
06:14The comparison is actually internal to sort_by.
06:17So it's making use of the same thing.
06:19It's just little more convenient to do it using sort_by.
06:23Finally, just to further illustrate the point, let's change it from length.
06:27Let's sort it by the reverse order.
06:31So what that does is it says okay, go to each one, reverse the characters, and
06:36sort it based on the word backwards.
06:38Now it didn't actually output the word backwards, but banana went first, because
06:42it ends an A, orange went second because it ends an E, and then G. If we look at
06:47apple, it's E and then L, which comes after G, and pear is at the end, it's R.
06:51So it's sorted it based on the alphabetical order if we reversed it.
06:55So I think you get the idea now.
06:57The last thing I want to show you is just that fruits for example hasn't changed.
07:01It's in its original order still, just like when I first defined it.
07:04But there is a exclamation point version just like there was for merge and collect.
07:08So we can have the same thing.
07:09Let's go up here to our long example. Here we are.
07:13We can just use our cursor and go over, and right after Sort, put an
07:17exclamation point, and now when we ask for fruits, it is permanently sorted
07:22instead of just being temporarily sorted, in which case we would have to catch
07:25it with a variable.
07:26The last thing I want to show you is that while arrays are typically what we
07:29would sort you can sort hashes as well.
07:32The thing is that Ruby turns a hash into an array to do the sorting.
07:36So let's take a look real quick at how that would work.
07:38I am going to put in a real simple hash here, C is going to be 222, A is going
07:42to be 555, D is 111, and B is 333.
07:45So if you want a sort of hash, what Ruby is going to first do is say hash to
07:50array and that's what it's going to turn it into.
07:52It's not going to be a hash anymore.
07:54This is very important.
07:55So when we talk to the code block, the first one will be this item compared with this item.
08:03So if we just compare the items themselves, well unless both the key and the
08:07value are the same, which is not possible in the hash, because the key can't be
08:11the same, they would replace each other, unless that's true, we have to do
08:15something else in order to make this a productive sort.
08:18Let me just show you that the hash still is the same.
08:20So we'll have hash.sort and then we are going to have item1.
08:25That will be that first one, item2, oops, I forgot my upright pipe, and the other pipe.
08:32And then, we'll do our comparison.
08:34Item 1 versus item 2, but we need to look at something inside item1, and this is
08:40the item at index 0.
08:42We know how to work with arrays.
08:45So the item at index 0, when compared with the item2 at index 0, and that will
08:53sort them by their keys A,B,C,D, or if we asked for item1, now it sorts them
09:01according to their values 111, 222, 333, 555.
09:05That's one important thing you need to remember about hashes is that they
09:08get converted into arrays, and so in that code block, you can't talk to it
09:11like a hash anymore.
09:12It doesn't have its key value pairs anymore. Instead, it is now an array that
09:17has two items in it and so you'll either be talking to the key or the value in your sorting.
Collapse this transcript
Inject
00:00In this movie, we're going to take a look at inject, which is another Ruby
00:03method that makes good use of code blocks.
00:05Well, it may help to know that inject is an accumulator.
00:08So that's what it's going to do.
00:09It's going to accumulate for us.
00:11So when you see the word inject immediately think accumulate, and if we're
00:15going to accumulate values then we're going to need a place to accumulate
00:18them, right, a variable.
00:19And so we'll have a block variable that will do our accumulating for us.
00:23And by convention, we call that block variable, memo.
00:26You can call it something else if you want, but most programmers are going to
00:29use memo and I suggest you do too, just to remind yourself that's what it is.
00:33That this is the accumulator where we're accumulating our values.
00:36I think it's also helpful before we look at inject to look back at collect for a second.
00:41We saw how we could have a range like 1 through 10 and use the collect method
00:44with the block and we would apply that block as a transformation to each one of the elements.
00:49Well, with Inject, we're going to be doing the same kind of thing but we're
00:53going to be taking that value and accumulating it each time and we're going to
00:58be storing it in memo.
01:00So that's going to be the difference.
01:01So now let's take a look at inject.
01:03So here we once again have 1 through 10, we're going to use the inject method
01:06and then we have our code block.
01:07There is memo right off the bat, we've declared memo as being the accumulator
01:12and then the invariable is where each one of the elements will be yielded up so
01:17that we can use it in our block, just like we had with collect.
01:19So now, our block needs to tell it how should I do this accumulation and the end
01:24result of whatever we put in there is what's going to be stored in memo.
01:29So, if we just put the number 1 there, then it doesn't matter how many elements
01:33at the end, memo is equal to 1, because every time it loops through, we just say oh!
01:381, 1, 1, 1. So memo is equal to 1.
01:41Now, what I've done here in this example is shown you a simple sum of all the numbers.
01:46So each time it's going to go through, it's going to take whatever value it had
01:49previously and add the next number to it and then store that in memo, then take
01:54the next value and so on.
01:55Let's walk through it just to make sure it's really clear.
01:57When it starts out, memo is going to be equal to 1.
01:59Now that's just because it takes the first value as its initialization values.
02:03So it will take 1 as memo and then it will go to the second value.
02:07When it goes to the block the first time, memo is already 1 so then we'll say
02:12memo equals memo plus 2, which is 3.
02:15It'll store that in memo and will go to the next time through.
02:18The next element is 3.
02:19So memo will be equal to memo plus 3 and so on, until we accumulate all of those
02:25values which is a sum of all the numbers 1 through 10.
02:27Let's start by launching an irb session with simple-prompt and let's
02:33create ourselves an array.
02:34Let's just say array equals, and let's use that splat operator, *1...10, and
02:41we'll make a full array, 1 through 10.
02:44Now, let's do the sum that we just saw.
02:45Sum equals and we'll take our array and we'll inject, declare memo and n and
02:55then we'll say memo+n is what should you do each time, storing the resulting
03:00value in memo automatically . So, the fact that the word memo is there,
03:04this is the process that we're doing.
03:06We are telling it use your old value memo.
03:09The results of this will be stored in the new memo value that will be passed to the next loop.
03:13So here it is, the answer is 55, and sure enough, if you take all the numbers 1
03:17through 10 and you add them up, you come up with 55.
03:19Now, you may have thought it was little peculiar that the first time through
03:23that memo gets set to 1 automatically and it doesn't actually apply the block to it.
03:28It only really applies the block the first time when it gets to 2.
03:31That's the behavior if we don't give it another value, but we can give it another value.
03:35We can say array.inject and then in parentheses here, we'll provide the starting values.
03:41So let's say 100.
03:42That's the initialization value of memo.
03:44So now the first time through, memo will be equal to 100 and the first number
03:49it adds to will be 1.
03:50Okay, so that will be the first iteration that will be starting with the number 1.
03:54Whereas before, it used the first number as an initialization value and
03:58the first iteration was actually with 2.
04:00So let's just try it and you'll see now we get 155, it starts with 100 and then
04:05it adds them all up.
04:06Of course, we're not limited to just addition.
04:08Otherwise we could just call it sum.
04:10But instead, we can do a lot more complex things.
04:12For example, let's say product equals array.inject and memo n and memo times n.
04:22So now, it will give us the product of all of those numbers multiplied together,
04:261 through 10 and just like the one above it, we could give it a starting value.
04:30For example, if I said, if the starting value is 2 then now, it will be that
04:35same number times 2 because it starts out with the value of 2 and then does all
04:39of its multiplication.
04:40Now just like we're working with the collect method, you want to be careful
04:43about the value that gets returned here.
04:45You want to make sure that it always is the value that you really do want to store in memo.
04:51Okay, so that whatever comes out of this, the resulting return value is what you want
04:56and if I instead said, well let's go through it but this time, let's do the
05:00plus n if n is not equal to 3.
05:05So we add it but only if n is not equal to 3.
05:07If we run that, we'll see we get an error and the error is essentially
05:11saying that it tried to use the plus, addition, when we had nil and you can't
05:16add something to nil.
05:18Nil is not the same thing as zero.
05:20What happened here is that when it looped through and it got to the number 3, it said, oh!
05:25well n is equal to 3, so I'm not going to run this at all.
05:29So none of this statement takes place.
05:31And the resulting value is nil and nil is what gets stored in memo.
05:36That's the end result.
05:37So, nil gets put aside and in the next time through, it tries to add nil and the
05:42number 4 together and it gives an error.
05:43So just be careful about that and make sure that the value you are returning
05:47really is the value you intend to store at the end of that iteration.
05:52Let me show you another example that frequently trips people up.
05:56It is something that we also saw earlier with collect which is if you do some
05:59kind of an output in here.
06:01So we're going to puts memo plus n. Well we get the same kind of error because
06:06the return value from this is nil.
06:09Now, one way to work around this, if we really do want to do that, we could
06:13also use an each method.
06:14That's probably the better way to do it, is to do each and do a puts that way.
06:18But if we're really trying to accumulate, what we could do is say well that
06:21final value ought to be memo, for example.
06:24A semicolon, let's just put it on the same line.
06:27So that's the one time we can use semicolons in Ruby.
06:29So now it does output results every time without giving us an error, but what
06:34it's actually doing is setting memo equal to 1 every time because it started out being 1.
06:38So, it puts 1 plus 2 which is 3, but then it says, "and your return value is 1"
06:44and so it just sets memo equal to 1 every single time.
06:47So, again, the overall point is just to be conscious that the result of all of
06:51this is what's going to be stored in memo for the next iteration.
06:55Hence, you want to make sure that is what you intend.
06:57Now, let's look at some more exotic examples that we could do.
07:01Let's say fruits, we got apple and we'll have a pear and let's have a banana and a plum.
07:09So there's our fruits.
07:11Now, right off the bat, you might think that you can't use inject with an array
07:15that's made of the strings like this, but there's no reason you can't.
07:18All we're doing is storing values for the next round. That's all it is.
07:22We're storing a value each time we go through that we'll then use in the future.
07:25So for example, let's try longest_word equals and we'll take fruits, we'll use
07:32inject and we'll use the do form this time because we're going to use it on
07:36multiple lines, fruit.
07:39And then let's put if memo length.
07:43So the length of whatever was stored before is greater than the length of
07:48whatever we are looking at now.
07:51So if memo is greater, we want to keep memo, but if not that means that fruit
07:57was longer and so what we want to save this time around is fruit.
08:02So each time we're just saving the string and in the end, it will tell us what
08:05the longest word was.
08:06So, it goes through with each one and does a comparison and says, "ah!
08:10This one is the best one I've got right now" and then the next time through,
08:13it says, "let's compare what we had last time that was our winner with what we've got now."
08:18Ah! That old one was actually still better.
08:20So let's keep apple around one more time because it beat out pear.
08:24So then we go to the next one and this is ah!
08:26But now, banana is longer.
08:28Banana is longer than apple so we're now going to store banana into memo.
08:32And then in the final round, it compares banana, which was stored, with the next
08:36one which is plum and banana is longer so it returns memo.
08:40So, that's its final result at the end and that's what it sets equal to the longest word.
08:44Real quick, I'm just going to give you another example of a place that you could
08:47use this kind of thing potentially in the real world.
08:50Let's imagine that you have a website and you have a menu bar that goes across
08:54the top that tells all about the company, okay.
08:56So let's say that menu bar looks something like this, a Home, History, Products,
09:01Services and Contact Us.
09:02That's the string that's going to be across there.
09:04We could use menu.inject and let's say that we have five characters of
09:10margin on either side.
09:11So there's five on the left, five on the right.
09:13We want to find out our total width.
09:15We could do that with memo in each item and then we could say memo plus the item length.
09:21And that will come back and tell us, your total width of characters is 47 and
09:28then we could scale that up to however many pixels and know how wide our website
09:31should be or something like that.
09:33So, I think the first couple of examples give the easy and common way that we
09:37would use memo but I think then these last ones show the more complex ways
09:42that we can use it.
09:43We don't just have to do math with it.
09:45We can do different kinds of comparisons and checking.
09:48There could be all sorts of stuff going on, but the end of the day, we just say
09:52okay, and for the next iteration, this is what you should keep around.
09:55That's the important part.
09:56That's what it does.
09:57It's an accumulator that accumulates values in memo and we can accumulate
10:01whatever we want in it.
Collapse this transcript
5. Methods
Defining and calling methods
00:00In this chapter we're going to talk about Ruby's methods.
00:02We are going to start out by talking about how we can define and call methods.
00:05Now we've been working with methods already, as early as when we were talking
00:08about the string class, we had Hello.
00:11and we put the Reverse method on it, and that reversed all the characters.
00:14And then we took the result to that, and we applied another method to it,
00:17the Capitalize method.
00:18And we did similar things, and we were looking at iterators and we were
00:20looking at code blocks.
00:22Now these methods are object methods.
00:23They're meant to be applied to an object.
00:26That's a little bit different than what we'll start out with, because we haven't
00:29learned about object classes yet, and we'll get to that in the next chapter.
00:32This is going be basically standalone methods that we're talking about.
00:35In a lot of other programming languages, they just call it Functions, but in
00:38Ruby we call them methods.
00:40The way you create a method is very simple, we have def, which is short for
00:44define, and then the name of our method, then we have end, at the end, and
00:48in between def and end is the code that we want the method to execute, when it's called.
00:53Defining method is that easy.
00:54Let's go to irb and create one.
00:56So I am going to have simple-prompt after irb, and let's try def, and we'll make
01:02a simple welcome method, puts " Hello World!" So there we are.
01:09We've defined our method now.
01:11Notice the return value of defining the method is nil, and it didn't actually do
01:15the code inside, right?
01:16The puts "Hello World!" didn't happen.
01:18That's because we've defined the method, but its code that's sitting there
01:21waiting for us to call it.
01:23And the way that we call it is just simply by giving the method name.
01:26There is no dot notation here, dot notation is when we are talking about object
01:29methods, which we'll get to, and we are just talking about standalone methods
01:32you just call the name, and you will see now it executed the code.
01:35It did the puts "Hello World!".
01:37The reason why methods are useful, the reason we're going to want to use them is
01:40because we can put large blocks of complex code inside them, and then call all
01:45of that complexity with one single name.
01:47Now, because we are talking about putting large blocks of complex code, it means
01:51that irb is going to stop being quite as useful for us as it has been, when we
01:55are using it for the simple calculations.
01:57So instead, we are going to move over to the file system, and start creating
02:00Ruby files that we can run from the command line instead.
02:03So I'll just quit out of that.
02:05Let me hide irb, and now you'll notice that on my desktop, I have got a folder
02:09called ruby_sandbox, and that's where I am going to be putting all this work.
02:12So I open that up, you'll see that there is already a file and they are called methods.rb.
02:16We'll open it up and take a look at in a moment.
02:18If you don't have the exercise files, you can pause the movie and copy down what
02:22I've got, but if you do have them, you can find this file there and make a copy
02:26into the ruby_sandbox. Let's take a look.
02:29I've just put some simple method definitions in there, I've got my
02:31welcome definition.
02:33I've also got add, which just adds one and one.
02:36I've got one called longest_word, notice the underscore between them, just
02:40like a variable names.
02:41This finds the longest word out of this array of words, and it uses the inject
02:46method that we saw from the last chapter.
02:47Finally, I've got a method called over_five?
02:50with the question mark at the end.
02:52Method names can have question marks and that can be really useful to indicate
02:56to yourself when you're using it that it is used for a test, that it's going to
03:00test some value, and either return the results of this test or maybe a boolean.
03:04Now in this case I am not returning just true or false, I am actually returning text.
03:08And now I am actually going to put that test, either over_five? or Not over 5.
03:12Now we have our methods.
03:14So let's save this file, and let's go back to our command line, and what we want
03:18to do here is navigate to wherever that file is.
03:21So cd and for me that's going to be inside desktop, inside ruby_sandbox, and
03:26that's where I am going to find that methods file.
03:28And then just ruby methods. rb will execute that file.
03:33It may not look like it did anything, but it did.
03:36It read in all four of those methods, it defined them, but then they didn't do anything.
03:40The same way up here we just did our definition of welcome, but then nothing
03:43happened until we actually called it.
03:45Now we need to call those methods.
03:48Well, there's a couple of ways we can do that, and I want to show you both of them.
03:51The first is that we can go back into irb, and we can use require, and require,
03:56and then what the name of the file is that we want to require in quotes and you
04:00can also provide more of a path information if you need to help if find where
04:04that file is, but if you are already in the same folder, you should just find it right there.
04:08So responded with true, which means that it was able to find the file, and it
04:12did read it in, and process it, right?
04:14So all the Ruby code that was in there was executed.
04:17So in this case, it made four definitions for us.
04:19So now we can just say welcome, and now we can call it.
04:23So we have access to all of our methods, over_five?
04:27and Not over 5 is what it returns.
04:29That's the first way.
04:30The second way is that we can actually open up that file, and in the file we
04:35can now say welcome.
04:37Now when we run the file, again, I am just from the regular command line not in
04:40irb, ruby methods.rb now it outputs those results to our command line, not to
04:47irb to our command line.
04:48It will output to either place.
04:50Now of course, if we go back in to irb, when we do this require now, it's going
04:55to do that output, we'll still be able to have some interactivity afterwards,
04:59but it will do the same thing just inside irb first.
05:04So I want you to feel comfortable being able to switch back and forth if we need to.
05:07The technique of going into irb is useful, if you want to continue to interact
05:11with it, after it's done.
05:13If we just want to run the script and then be done with it, then we can just
05:16simply run it from the command line.
05:18So let's switch back to methods now, and let's go ahead and call our other ones.
05:21We have add, we have longest_word, and we over_five? There we are.
05:28So once again, I'll just run Ruby methods, and you'll see that it does all four
05:32of those successfully.
05:33One last point I want to make is that we do have to define our methods before we call them.
05:37So I have just added a little note here that's probably commonsense, but it does
05:41read this page in order, and so things get processed in order.
05:45For example, if we were to put welcome up here at the top before it's been
05:49defined, we'll Save it.
05:50We'll go back and run it.
05:52You'll see it comes back and says, "oops!
05:53I don't recognize that, I don't know what to do with that."
05:56So we do have to do the definition first.
Collapse this transcript
Variable scope in methods
00:00Now that we have seen how to define Ruby methods, I want to take this
00:02opportunity to take a look at variable scope.
00:05We first talked about variable scope back when we introduced variables, and at
00:08the time I told you that we really wouldn't be able to go into it in any kind of
00:11depth until we had some more complex Ruby structures that we could look at and
00:15see how variables interacted in those context.
00:18We revisited the subject again when we got to blocks and now that we have
00:22methods, we can see how variable scope applies to methods as well.
00:26In my ruby_sandbox, I have now got another file called method_scopes.
00:29Its basically the same file that we were working with, I just saved a different
00:32copy of it, so that I could keep the work separate.
00:34I have also removed all the comments that we had made.
00:36You will notice in our method definitions we are using local variables in a few
00:40places, words, longest_word, and value.
00:44We have also got block variables, word and memo that we are using.
00:48We have already seen how block variables work.
00:50I want to focus on the local variables.
00:52Now, the reason why they are called local variables is because their scope
00:56is local to the structure that they are in, and methods are exactly that kind of structure.
01:02So value = 3 only has scope inside the method over_five.
01:08Now, when I say it only has scope, that means that it is assigned inside there.
01:12It can be used inside there, and when the method is over, that variable will be
01:16discarded and can't be used outside of the method.
01:19We can see that if we go down here below our method calls and we just do puts
01:23value, and then we will Save our file.
01:26Let's go back into our command line, notice that I am already inside my
01:30ruby_sandbox, and from there I will run my new file method_scopes.rb.
01:35So it ran our code successfully.
01:37We got all the results from the methods that we would expect.
01:40But then when we got to outputting the value, you will notice that we got
01:43undefined local variable.
01:45That's because value has not been set inside this scope, the global scope of
01:51this file, it was only set inside the scope of the method.
01:55The same thing is true if we were to set a value, let's say, at the very top of
01:58the file, value = 7, so now we will Save that.
02:04If we run it again, now this time we didn't get the error because value was set, value is 7.
02:11It didn't change it when we ran our method.
02:14Either defining it or calling it did not change it.
02:16Completely separate, and it still says it's not over_five.
02:20It didn't use 7 as a value, and it didn't change what we had.
02:23They are two separate variables, value and value, because they have two separate scopes.
02:29The same thing would be true if we tried to output the value of words.
02:32However, longest_word is going to be a little bit different. Can you guess why?
02:36Let's try just doing puts longest_word.
02:41
02:41We will save that file.
02:42We will go back to our command line and let's run it one more time, and notice
02:47what we got this time.
02:48We got banana and then we got banana again.
02:52Now, you might be thinking that it actually output banana from here. It didn't.
02:57What it's doing is it's putting the method, longest_word, that's what it's putting.
03:02That's why we get this sort of strange nil down here, at the very bottom, is
03:06because that's actually the result of this value that comes back.
03:10It's putting the longest_word here.
03:13That's when we see the word banana the second time, because we have called the
03:16method, and the return value from this puts is nil.
03:20We saw that earlier in irb.
03:22So therefore it's now outputting nil, and that's why we get that other nil there.
03:25So our variable name and our method name are the same, and that's where we are
03:31getting this confusion.
03:32So that brings up the point that you want to be careful when you name your
03:35methods to make sure that it's not confusing and that Ruby can always tell
03:39which one you mean.
03:40Now in reality, once we start programming with Ruby, it's really not that often a problem.
03:44I just want you to be aware of it, that your method names and your local
03:48variables are going to look the same, and so you want to make sure that it's
03:51always clear which one is which.
03:53Now, what about the case where we do want to be able to bring in something
03:57from outside the scope?
03:58I am going to go ahead and just comment this puts longest_word out for now.
04:02So let's say, for example, we wanted to have a word list that was defined before
04:07we ran it, and we wanted to make use of it inside there.
04:10There are a couple of ways that we can do it.
04:12One is to have a variable whose scope does stretch inside there, and an instance
04:17variable is that kind of variable.
04:19So we put the at symbol in front of it, now it does run successfully.
04:23Let's go ahead and run it one more time to see everything worked out just
04:26like we would expect.
04:28That's because this array is available inside longest_word.
04:33In fact, we don't even have to have it available before we define it.
04:36It just has to be available before we run it, right?
04:39It has to be available down here.
04:40Let's take a look at the variable types again.
04:43You recall that we had five variable types:
04:45Global, Class, Instance, Local, and Block.
04:48When we are working with methods, the things that will have scope inside the
04:51method are going to be Global, Class, and Instance.
04:54We can use any one of those, and it will still be available to us inside that method.
04:59Local and Block are going to have scope that's limited and does not go into the method.
05:04We don't have it available to us once we are inside the method scope.
05:08Now, there are times when it's perfectly legitimate for us to do it this way,
05:12to have a variable that's set outside of a method and then use it inside the method.
05:18We will especially be using that when we start looking at classes, but most
05:21of the time you want to use this very sparingly, because let's say that words had not been set.
05:26Well now, longest_word is expecting the we have set that, and if we forget to do
05:30it, then our method no longer works.
05:32It becomes fragile and it breaks.
05:35A much better way would be for us to pass in the variable that we want to use at
05:40the time that we call the method, and we do that with arguments.
05:43We can see how to do that next.
Collapse this transcript
Arguments
00:00In this movie I want to talk about arguments.
00:02When I say arguments, I don't mean the disagreement between two people.
00:06In programming, arguments are going to be a comma-separated list of values that
00:10we pass into our methods.
00:12It's a way that we can get around the problem that we saw in the last movie of
00:15variable scope, because now it doesn't matter what the scope is, when we call
00:19the method, we pass in the values that it's going need.
00:22We don't have to make sure that they have all already been set.
00:24We pass them in at the time that we call them, and that's going to be arguments.
00:27You will also sometimes see arguments abbreviated as just args, so if you see
00:33that, that's what it means.
00:34It's just short for arguments.
00:37In my ruby_sandbox, you will see that I have a file already called arguments.
00:40It's basically the same code that we have been working with, but I have added
00:43a comment to the top, noting that methods with arguments typically use parentheses.
00:48Methods without arguments typically do not.
00:51But it's completely optional as to whether we use them in both cases.
00:54So that's just sort of the standard.
00:56If we have something that's just welcome and we don't need arguments, we don't
00:58put the parenthesis, but we could, we would just put parenthesis after it.
01:02If it was going to have arguments, then we probably would put them, but we don't have to.
01:07In order to make arguments work, we are going to need to have a local variable
01:10that's going to catch those values as they are passed in to our method.
01:15So for example, name.
01:17Now we can make use of that local variable inside our method, and it has the
01:22same scope as we had down here when we defined value.
01:25Just to show you what I was talking about with parenthesis, we could just leave
01:29off the parenthesis as well and that would work.
01:32Typically you don't see that.
01:33You usually do see the parenthesis.
01:35Now our welcome method is expecting to receive one argument which it will assign to name.
01:42Let's try it out.
01:42We will go over to our command line, notice that I am already inside my ruby_sandbox.
01:48We will type ruby arguments.rb.
01:52Notice that I get an error.
01:53Welcome gave me an error, wrong number of arguments (0 for 1).
01:58That's the important part here.
02:00I sent it zero arguments and it was expecting one, and that's the important
02:05point about arguments.
02:06Once we have defined an argument here, it's expecting to receive it.
02:09We are essentially saying hey, I need this before I can keep going.
02:13So when we call welcome down here, we now have to put in a value, like Mary.
02:19Now it will pass in the string Mary as a value that will be received by the
02:24local variable name and then used inside. Let's try it.
02:29ruby arguments, Hello Mary!
02:31And the nice thing about that is now it's reusable, we could have Hello Mary! and Hello Larry!
02:37We can call it twice, and the only thing that we are doing different is we are
02:43sending a different value inside for it to use.
02:46Before we go on, let me also just show you that when you call these values as
02:49well, we don't have to put the parenthesis.
02:51We could have Hello Mary! Hello Fred!
02:55There we are.
02:56I left off the parenthesis around it.
02:57It's still an argument that's being passed in, ruby arguments, Hello Fred!
03:02Now up here, typically we do put the parenthesis with arguments, down here when
03:07we are calling it, it's really a matter of personal style.
03:10Some Ruby developers do it one way, some do it the other, there's no right or wrong answer.
03:14It's really a matter of your personal preference.
03:16Throughout the tutorial, I am going to put them in there, because I think it
03:18makes it clearer for beginners especially to see where the argument list starts and stops.
03:23We can also add arguments to our add method up here.
03:26We will put our parenthesis and we can put multiple arguments, n1, n2.
03:31Remember it's a comma-separated list of values.
03:33So the commas will know where to break each of those values, and then we can
03:37make use of those, n1 and n2, and we will need to pass those in down here.
03:42So let's say 2, 2, not 2+2, 2, 2, those are each of the arguments that are
03:49being passed into it.
03:50Let's take a look at longest_word.
03:52We could have, for example, the word list being sent in.
03:55This is a lot better than the other solution we were looking at earlier.
03:58Remember we were doing something like this, where we had the instance variable
04:01that was being used.
04:02Well now, we can just take our words, we will just come down here before we call
04:07it, and let's actually rename them to fruits.
04:11We can pass in fruits as an array.
04:14It will then become the local variable words once we are inside.
04:20It might have been fruits.
04:21It might have been cars.
04:23It might have been dogs. It doesn't matter.
04:25Once we pass it in, it gets assigned to words, and we work with it then as the
04:29local variable word.
04:31Let's change over_five to just be value, and now we just take this out and
04:36over_five, we can pass in a value.
04:38Let's pass in 8 this time.
04:39I will just put some spaces in here so we can separate these out and see all
04:43the different ones. Save it.
04:45Let's go back and run it one more time, and you will see that everything works,
04:49all my arguments get passed in successfully.
04:52Now our methods are much more usable because now they are flexible and we can
04:55use them in lots of different contexts, and we don't have to go to the trouble
04:59of setting instance variables or anything like that.
05:01We can just, at the time we call it, we can pass in the values that we want it to use.
05:05So, for example, over_five becomes a lot more useful now that we can do
05:09something like 112/18.
05:12I don't know off the top of my head whether that's going to be over_five or
05:15not, but we can run our method and find out that, yes, it is in fact going to be over_five.
05:20As you can see, arguments are what give the real power and flexibility to our methods.
Collapse this transcript
Argument default values
00:00In the last movie we saw how if we didn't send the same number of arguments to
00:03our method as it was expecting, that we got an error.
00:06In this movie we are going to see how we can use argument default values
00:10to avoid those errors.
00:12You will see that I have a new file on my ruby_sandbox, its argument_defaults,
00:15and I will open it up.
00:16It's basically the same file that we have been working with, just a little bit cleaned up.
00:19The case that I want us to look at is how we can set a default value so that,
00:22for example, if we called welcome, and we just called it by itself and we did
00:27not send anything, that there would be a default behavior that would happen
00:30instead of giving us the error.
00:33The way we do that is we just go ahead and make an assignment to this variable
00:36inside the argument list.
00:38So Hello World, for example.
00:40Now when we call it, we don't get an error anymore, because even though we
00:44didn't send an argument, it was satisfied because it said, ah, my argument did
00:48get a value in the end, not one you sent to me, but one that I set myself.
00:53So it's the equal sign right after it.
00:56If we have multiple arguments, you just assign them each, like =0 and then for
00:59this one, =0.Let's go ahead and just try that out.
01:02Let's just say add, and for add, let's go ahead and submit 3.
01:06We will just put in one argument.
01:08So we are going to add 3.
01:09It doesn't really make sense, but that's what we are going to do.
01:11We will go into our Terminal.
01:13Notice that I am already inside ruby_sandbox, and I will just run
01:17ruby argument_defaults.
01:20So there it wrote Hello Mary!
01:22Then we get Hello World!, the default behavior.
01:25We added 2 and 2 and we got 4. We added 3.
01:28It just came back with 3.
01:29Because we sent 1 and it got used here as n1, and then n2 got assigned the value of 0.
01:38Obviously, the order of our arguments is going to be important.
01:41It has to know which one of our values to assign to which one of these slots up here.
01:45So, for example, 3 would never end up being n2.
01:49Its always going to get assigned to n1, because it's the first value.
01:53If I put something else in front of it, nil, let's say, then nil would get
01:56assigned to n1, and 3 would get assigned to n2.
01:59So the order does matter.
02:01You want to be careful about that.
02:02Therefore, you will want to make sure that you put all of your required
02:05arguments up at the front.
02:07You could do n1 and then n2.
02:09So n2 is optional now, n1 is required.
02:12If I did it the other way around, this isn't really that useful.
02:16It's going to give me an error unless I provide both.
02:19There's no circumstance where I can just provide 1 to it.
02:22If I just give this, add 3, it would say oh, n1 is equal to add 3, but n2 gives me an error.
02:28It's not really that flexible.
02:29So you just want to make sure that if you have some that are required and some
02:33that are not, the required ones are the first ones there, so that then as you go
02:37down the list, the optional things come later on.
02:40Now, we have already seen how we can put a string and an integer as being the variables.
02:45We can also put in arrays as a default value.
02:47So there's just an empty array, two square brackets side-by-side.
02:51That's going to say look, if you don't get an array, then set yourself to an
02:54empty array, which a lot of times will keep your method from blowing up on you,
02:58because it will then have a default value.
02:59So if you are doing like each, for example, doing each on an empty array will
03:04just not do anything.
03:06But having nothing assigned to it will give you an error saying, "oops, you
03:10didn't send in the value, I am not very happy with you," kind of thing.
03:14So let's try that down here.
03:15Let's just try longest_ word and see what we get back.
03:19Then same thing with over_five.
03:21Let's try setting it to nil.
03:22We are going to say if you don't get a value, then don't object, don't raise an
03:27error, just set value equal to nothing.
03:30Don't pass an error, just keep on going, because I am okay with the fact that I
03:33might not have gotten value.
03:36Let's just do over_five by itself and see what we get now.
03:40So let's try all this out.
03:42We will come back over here, and defaults.
03:44Now, notice that over_five still raised an error, but the error was
03:47different this time.
03:49The error this time was, undefined method > for the NilClass.
03:54So it basically said, well, I don't know how to handle that with nil, if we were
03:58to instead just put a to_i on it to make sure that it changes it into an
04:02integer, then we can get it to pass.
04:05So now it goes through and it says, "ah, I got nil."
04:08I am going to convert nil to an integer, which is going to be 0, and therefore
04:13it will say, "ah, 0 is not greater than 5."
04:16So we got an error, but the error was not an argument error.
04:19When you are programming and you are defining your methods, it's always a good
04:22idea to stop and take a second when you are making your argument list, and think
04:26about what really is required for this method to do its job.
04:30For example, over_five, having nil really doesn't make a lot of sense.
04:33So we might say you know what, if you are going to use over_five, you have
04:36to send me a value.
04:38Now, we still might want to do this to_ i in case we were to send a string or
04:40something like that.
04:41It's not a bad idea.
04:42But if we leave it out, then we are basically saying you must send me a value.
04:46If we put in something like 0 or nil, then what we are saying essentially is
04:51it's okay if you don't, I will handle it, I will live.
04:55So as you are making your argument list, always stop and think about where your
04:58default values ought to be.
Collapse this transcript
Return value
00:00In last movie, we saw how we could use arguments to get values into our methods
00:04so that we could use them.
00:05What about getting values back out of the methods?
00:08For that, we need to take a look at the method Return Value.
00:11In my ruby_sandbox, you'll see I have a new file now called return_value.rb.
00:15If we open it up, you'll see this is basically the same file we've been working
00:17with, just pared down a little bit.
00:19Now we've already been working with return values without really knowing it.
00:22Now, we have already seen return values when we were working in irb.
00:25Let's go back and just open up an irb session to remind ourselves.
00:29I'll just open one without simple-prompt.
00:31If we have 1+1, we're not doing a puts, right?
00:35We're getting the return value of 2.
00:37If I do puts 1 +1, then we are outputting 2, and our return value is nil.
00:43And we talked about that puts always has return value of nil.
00:46So that was true in irb.
00:48It's also true back here in our method definitions.
00:51So when we call welcome, it runs puts, which outputs what we asked it to, and
00:58then there's a return value for it.
01:00Now, if there is another statement then that return value just gets ignored, and
01:04we keep going with everything else.
01:06But what happens at the end of the method is that the return value for the whole
01:10method is whatever the last thing was.
01:13So in this case, when we were doing a puts, the return value is nil, we can see that.
01:17Let's go down here and let's say returned_value = welcome("John") and then
01:26puts returned_value.
01:29So now we can actually see that value. Let's save it.
01:31Notice that I'm already in my ruby_ sandbox here, and I'll just run ruby and
01:35then return_value.rb. So here we are.
01:38It runs the Hello John!
01:40that's when it calls the method, because it's still calling it here, still calls the method.
01:45But then we are catching the value, and we are putting it again, and that's the
01:49nil that we're seeing here.
01:51So they all have a return value automatically.
01:54If we put 1+1 at the end, and save that, now let's run it again.
01:59Now, instead of nil we get 2.
02:02So whatever the last value is inside the function is what gets returned by
02:06default, and is the exact same thing as if we said return, return this value.
02:11So that is the way we're very explicit about it and say this is what I want you to return.
02:16And return not only returns a value, it returns from the method.
02:21So it exits the method at same time.
02:24So if, for example, we did 2+2, our code will never get there.
02:28It will never do the 2+2, because as it's executing, it will do our output, then
02:34it will come and do 1+1 and figure out it's 2.
02:36It will return that value to us so that we can catch it and work with it and it
02:41will just stop right there.
02:43Let's try it, and you will see that we get the exact same thing back, we did not
02:47get 4 as our return value.
02:49So that's the second point.
02:50So the first point that I made is that all methods have a return value, even the default one.
02:55So there is always one, even if we don't catch it.
02:57So in the case of welcome ("Mary ") here, we just won't catching and
03:00doing anything with it.
03:01The second point is if we're explicit about it and we say return, and then we
03:05return from the method and we are done.
03:07Now most of the time what we want to return is the result of the processing
03:11that the method does.
03:12So for example, I'll take out the 1+1, and now we'll just do return "Hello #{name}!.
03:16So it has the same effect, 2+2 will never get executed, but the return value
03:21will be the result of whatever welcome method did.
03:24It's processing and it did.
03:26In this case it just made a string for us.
03:28Now, let's just save this, run it again, notice that we don't get Hello Mary! anymore.
03:34We just get Hello John!, because calling it here did nothing.
03:37All it did was to generate the string, return the value, and then it got thrown
03:41away, because we didn't catch that returned value.
03:44In the case of welcome John, we did.
03:46Now it's a little bit up to you as to whether you put the puts statement
03:49inside your method or outside the method, and it really depends on what the
03:53method is meant to do.
03:54If the purpose of the method is to do some output, then it makes sense to put it in there.
04:00But otherwise it might make more sense to put it outside, and that way we can
04:04put it when we want to put it, like we did here when we did puts
04:07returned_value, or we could not, like we just assigned it to returned_value, we
04:12could to do something with it.
04:13Let's say for example here with longest_word, return the longest_word at the end of it.
04:18So now instead of having the longest_word, let's puts the
04:23longest_word (fruits).length.
04:25We won't get banana anymore.
04:27Instead now, we'll get the length of that word.
04:31We don't care what the word was, we want to know how long it was.
04:33It's 6, and maybe we're going to use that for some purpose.
04:36So not having the puts inside the method a lot of times gives us
04:40greater flexibility.
04:41Doesn't mean you have to.
04:42It's perfectly valid to have a method that it does output.
04:46Now so far, the return that we've been doing has been at the end, where we were
04:49basically saying well, return this after we are done all the processing.
04:53But we don't have to, in fact that's the real power of return, is that it works
04:56well with if statements.
04:58So for example, here I have said return "Exactly 5", if the value is 5.
05:03Don't go any further.
05:04We're just going to call it done, and if not then do this additional process, in
05:08which case I have another if else statement.
05:10Now obviously you could have written this all as one statement.
05:12But I wanted to show you the way that we could do return if, because this is a
05:16common Ruby idiom that will do return something if this is true.
05:20Exit the method right away if certain conditions are met.
05:23And then if we want this to work, of course, we'll need to do, puts over_five or
05:28else catch that string and do something else with it.
05:30So frequently return is used not just at the end of the method, but at various
05:34points within the method.
05:36Now, the last and perhaps most important point I want to make about a return
05:40value is that it's singular.
05:42There is only one return value that comes back.
05:46So let's rewrite our add method so that we would like to return two values from it.
05:50Let's say add_and_subtract, and we need a method that will do both for us.
05:54It's going to take n1, and figure out what their addition is, but it's also
05:59going to do subtraction, say n1-n2.
06:03How can we return both of those values back?
06:06When we have multiple values to return, the way to do it is to put them in a single object.
06:12In this case an array.
06:13So add and subtract.
06:15Now that is one object, its one return value, but inside there are other
06:21multiple values, and that's what you get around it.
06:23So we can only return one object from a method.
06:27But that object could have multiple objects inside of it.
06:31It could be an array.
06:31It could be a hash.
06:32It could be some other more complex object that contains lots of other stuff.
06:37Frequently, you'll see the Ruby developers just leave off these are square braces.
06:41So this will just be return add, sub.
06:43It's still returning an array. That's what it is.
06:46Those square brackets are just optional in this case, so we don't actually have to have them.
06:49But it is still an array and when we get the value back, we'll need to treat it as an array.
06:54For example let's do now add_and_ subtract, and let's say result = so we'll need
07:02to puts result and the 1 item and puts result and the 2 item.
07:11So those are going to be the two items in our array.
07:13Let's just try that out.
07:15Ruby return_value.rb, and here we are, we get our value 4 and 0.
07:19So, 2+2 is 4, 2-2 is 0.
07:22Another neat trick that you can use is you can do double assignment.
07:26So we could say for example, add, sub = and then let's do, add_and_subtract and
07:33we could do something like 8 and 3.
07:37Add, sub is actually an array as well, just with those square braces missing.
07:42But it does the same thing.
07:43It does double assignment now.
07:44So now when an array comes back, the first value of the array goes into the
07:48first one, and the second one goes into the second one.
07:51And that's a nice, convenient shorthand to know about.
07:53Otherwise you get little bit confused when you say wait a minute add, sub =,
07:57how is that possible?
07:58Well that's what it means.
07:59It means that this is returning two values back and we are catching both of them
08:03into this array of variable assignments.
08:05So just to recap those points we've seen about returned values, methods already
08:10have a default return value, and it will be the last operation's return value.
08:15We can explicitly use return, and it will both return the value and exit the method.
08:19I also suggested to you that returning a value and using puts outside of a
08:24method can be a lot more flexible than if you were to just simply do the output
08:27from inside the method.
08:29And we saw how return is especially useful with conditional statements, and that
08:32methods could only return one object.
08:35You will want to use an array if you need to return more than that.
Collapse this transcript
Operators are also methods
00:00You'll be very surprised and quite possibly amused to discover how prevalent
00:05methods are in Ruby, and you didn't even know it.
00:08Common operators in Ruby are methods too.
00:11When I'm talking about operators, I'm talking about things like Plus. Plus is a method.
00:16Now in most other languages, you would just say it's an operator.
00:18It's just very simple, 8+2, just like on a calculator.
00:21Now in Ruby, it's actually a method.
00:24It's the plus method that's being applied to the integer 8 and the
00:28first argument is 2.
00:30So the name of our method is that + there.
00:33Instead of having it be a word in English that we'd recognize, it's just the +.
00:37Both of these will work if you go in the IRB and try it out.
00:40Now we've already seen how the parenthesis around the argument list is optional.
00:45We saw that back when we were talking about arguments.
00:47But there is another change that's happening where Ruby is allowing us to
00:51just put + instead of having to put dot plus, and that's something that's
00:56happening internally in Ruby to make it easier for us to use, so we don't
00:59have to do it the cumbersome way.
01:01Instead, we can do it a slightly sweeter way, and that's why we call it
01:04syntactic sugar, because it's made the language a little sweeter for us.
01:09The syntax of the language is a little sweeter, because it's much easier for
01:13us to write expressions like 8-2, 8*2, 8/2 and 82, then it is to write the
01:20method names for them, eight dot minus and then parenthesis, whatever argument is, and so on.
01:27But the column on the right is absolutely what's going on in Ruby when you type
01:31what's in the column on the left, and both of these will work.
01:33We'll try it out in a moment to actually prove to you that it does work.
01:37But let me show you a few more.
01:38Let's say that we have a simple array, and to that array we're going to append 4 to the array.
01:43Then we're going to ask for what's at index number 2 to be brought back out of
01:46the array, and then we'll set the value of what's at index 2 with the string
01:52X. These are also all methods that look like operators, but they're actually methods.
01:58The first one is pretty similar to what we saw before.
02:00It's just the .<<, and then the argument that's being passed in.
02:05Again, syntactic sugar makes it nicer and easier.
02:08The second one might not be as obvious how it's working.
02:11The name of the method is actually square bracket, square bracket.
02:15That's the name, and then the argument is what's inside those square brackets.
02:19Ruby just uses syntactic sugar to rearrange things a bit.
02:22The last one works in a similar way, but what's surprising about it is that the
02:26= actually becomes part of the method name.
02:28So the method name being applied is square bracket, square bracket =, and then the first argument is the
02:33index and the second argument is the value that should be put into that index.
02:37Thankfully, we don't have to ever write it the way it is on the right-hand
02:41side of the screen.
02:42We get to use syntactic sugar and write it the way it is on the left side of the screen.
02:45But here's the reason why it's important to understand this.
02:49You can name your methods with these kinds of symbols.
02:53So if you have something like you have a classroom and you want to put a student
02:57in the classroom, you can write a <<, append method of your own that will put
03:03the student in the classroom, or if you have a long string, let's say it's a
03:06page of text, and you want to break it up into thirds, you could use the divisor
03:10method, and use the slash that we'd use for dividing.
03:13It wouldn't mean to divide in the normal sense of dividing, it would mean, take
03:17this page and divide it up.
03:19So keep that in mind when you're naming your methods that you can make use of
03:23the syntactic sugar for yourself.
03:25Now that we understand that these are methods being applied to objects, we can
03:29revisit something we saw earlier, which is that hello, the string, multiplied by
03:345 gives a different result than 5 multiplied by the string, hello.
03:39The first time we'll just get hello five times, the second time we'll get an error.
03:44The reason why is because the first is taking a string and using its multiply
03:48method on it with the argument 5, which does have a valid result.
03:52The second is something different.
03:54It's an integer that is using the multiplication method, which integers when
03:58multiplied by something, and we know what they'd do, right, 5x2 is 10.
04:03Well, when you pass it a string, it says, "wait a minute.
04:06I was expecting it an integer.
04:08That's how multiplication works."
04:10So a string has a different behavior, because it's a method on the string
04:13class, whereas it works differently when we have the multiplication as a method
04:18on the integer class.
04:20So as promised, let's try all these craziness out and prove that it still works.
04:24So here I am in my ruby_sandbox, and I've got a file called syntactic_sugar, I'm
04:28just going to open that up.
04:29It's already pre-populated with everything.
04:31I've just got those same things that I had in my slides.
04:34So first, I've got the nice syntactic_ sugar version, and then right below it,
04:37I've got the not so nice version, which we could also call syntactic_vinegar,
04:41where it's not so tasty.
04:43So we'll have one after another, and they should give us the same values all the way down.
04:47Then when we get to the arrays, I went ahead and created a simple array.
04:50I just called array1, [1, 2, 3], and I've got a second one, array2.
04:54Now this is actually an actual equal sign.
04:56It's an actual operator where we're doing a variable assignment.
04:59It's not a method on an object, because remember our variable is not an object.
05:04That's one of the few exceptions to things that are not objects, is a variable.
05:07So then I'm going to go through and just perform each of these operations to
05:11either array1 or array2, using either syntactic_sugar or syntactic_vinegar, and
05:16then I'll just inspect it each time to see what it looks like.
05:18So let's just try it.
05:20I'm going to go into my command line and I'm already inside my ruby_sandbox, so
05:24I just need to do ruby syntactic_sugar.rb.
05:28There you go, they give the exact same results all the way down the line, works
05:32exactly like you would expect it to.
05:34Thankfully though, we're able to use the syntactic_sugar version most of the
05:38time we're programming, but it's still useful to know what's actually going
05:41on behind the scenes.
Collapse this transcript
6. Classes
Defining and using classes
00:00In this movie, we're going to be looking at classes.
00:02Classes are the backbone of object-oriented programming, because classes define objects.
00:07They tell what an object is and they define what an object can do.
00:11Now we've been working with objects already.
00:12We've seen that pretty much everything in Ruby is an object.
00:15But those are Ruby's objects, the ones that are predefined for us.
00:18This is going to be where object- oriented programming really begins for us,
00:22because now, we're going be able to write our own classes that will define our own objects.
00:27In order to get started with that, we first need to see how to define a class,
00:30and the syntax is very simple.
00:32It's just class and end with the definition of our class in the middle, very
00:36similar to what we had when we had methods, we had def and end, now it's class.
00:40The one big difference though is the naming of the class.
00:44Methods were all lowercase with underscores between the words.
00:47Class names are going to be what we called CamelCase.
00:50We call it CamelCase because it has the humps in the middle like that capital N.
00:54Well, the idea here is that each word is capitalized, but they're all smushed together.
00:59We don't have underscores at all, so we still have readability, because each
01:03word is broken up with a capital letter, but it's all one word, and most
01:06importantly, it begins with a capital letter.
01:09That's very important, class names have to begin with a capital letter.
01:12So it wouldn't matter here really if we had SomeName and it was a lowercase n,
01:16or if we wanted to capitalized the n. So it's up to you when you define it,
01:20whether you want to call it Somename with a lowercase n or SomeName with a
01:23capital n, but the s has to always be capitalized for a class name.
01:27Now classes are going to do a number of things for us.
01:30But one of things they're going to do is they're going to group our code into
01:33discrete well-categorized areas that make it easier to work with.
01:37So at the very beginning, what we're going to learn to do is wrap up methods
01:40inside there, and see how we can take the methods that we just learned in the
01:43last chapter, and put them inside our classes.
01:46Let's try creating our class with a method in it.
01:49So to start out with, let's just open up IRB, irb --simple-prompt.
01:55Let's try creating a class.
01:57So let's say just class Animal, right, there's my capital letter A in front.
02:02That's very important.
02:03Then I'll start a new line and then typically you'll indent everything after
02:07that, so that it's very clear where the class begins and ends.
02:10So let's put a method in here.
02:12Let's call it make_noise, and it's just going to make the noise of an
02:17animal Moo, let's say.
02:19You'll remember that there is a implied return there, right.
02:22The return value is the default return value of just the string, Moo, so that's
02:26what will be returned, and then end. Now it's set.
02:30It defined it for us.
02:31The return value was nil from doing that, just like when we defined the method.
02:35It didn't actually do anything besides the definition.
02:37We have to actually activate it, right, actually call upon it to do something.
02:42The way we do that with classes is that we create a new object from the class.
02:47So let's say Animal.new to start with.
02:51That creates a new animal.
02:52That's all there is to it.
02:53But we need to hold onto that once we've created it, so we're going to assign
02:56that to a variable, animal = Animal.new.
03:01Now, I created a new object, and now that object is being held by my variables.
03:06So I can always just say Animal, and there it is, my variable Animal
03:11always points to it.
03:12Now I just want you to see, if we just call make_noise on its own, it says,
03:18"oop, I don't know what that is." make_noise, no idea.
03:21make_noise is inside the class Animal.
03:24So we need to tell Animal to do the making of the noise, and we do that with the
03:28dot notation, animal.make_noise. There we are.
03:32It returns Moo.
03:34So it did what we asked it to.
03:35It called the method make_ noise inside that object.
03:39So notice what we've done here, we took an object, assigned it to a variable,
03:44then we told that object, call your method make_noise.
03:48Now what it returned to us is a string which is an object and we can do things
03:52like make_noise upcase.
03:54We can daisy-chain them together just like we can any other method anywhere else.
03:58All we've done now is write our own method on our own custom object.
04:03Notice also that we can't do this animal.make_noise, but that comes back and
04:08says, "oh, sorry, you can't do that either."
04:11And we'll talk about that in a little more depth later on.
04:14But I just want you to see for now that make_noise, we have to have that object
04:18created from the class, then we can tell that object to do things.
04:23So why is defining our own objects so important?
04:26Why is it a good thing?
04:27Well, it's because objects let us organize our code into well-categorized areas.
04:32Then it's easy to find things.
04:34So the instance of our Animal class, any code having to do with an animal could go there.
04:40Then if we said, oh, you know what, we need to make a change to our code, having
04:43to do with animals, we know right where to go.
04:45We'd go to the Animal class.
04:47The second benefit is that objects carry around their classes code.
04:51So all those definitions that we put inside of a class, they're always available
04:54to us, if we have that object.
04:56So that variable now, animal, that contains an object.
04:59We can pass it around, we can pass it into methods.
05:02It's an object, just like any other object.
05:04We can pass it in, like with a hash, we can put it inside a hash, we can put it
05:08inside an array, and it will always still have all those behaviors like
05:12make_noise available.
05:14The third thing is that it allows complex behaviors using very simple statements.
05:19Imagine for a second that we have two classes.
05:21One is a classroom, like in a school, and the second is a student.
05:26We want to put the student in the classroom.
05:28Now we can just simply say classroom.add student, and it will add the student to the classroom.
05:33But a lot of stuff can be going on behind the scenes there, we can be assigning
05:37the student to a default seat, we can be generating a name tag for them, we can
05:41be notifying the head office that they've been assigned.
05:44A lot of stuff can be going on behind the scenes, just by using very simple statements.
05:49Last of all, our object are going to correspond to real-world objects.
05:53That makes it easy for us to take abstract code, and think of it in a concrete way.
05:58So in the example of our classroom and student, we're not thinking about all
06:02of the 0s and 1s that have to get moved around to get those things to happen,
06:05we can just think about it in very real-world terms, classroom.add student,
06:11and so the student gets added to the classroom, student sit at desk, and then
06:15we can use common sense and regular English phrases to describe what we want our code to do.
Collapse this transcript
Instances
00:00Now that we know how to define a class and how to create an object from it, we
00:04need to talk about instances, and have an understanding of what an instance is,
00:07because an instance is a fundamental concept in object-oriented programming, and
00:11it's going to be central to working with classes.
00:13Outside of programming, the typical definition for instance might be a case or
00:18an occurrence, an example put forth.
00:20So what we are talking about when we talk about programming is a very similar thing.
00:24We are talking about an occurrence of our class. That's what it is.
00:28It is an object that's being created from a class.
00:32So when we created Animal.new, we created an instance of the class animal, and
00:37then we assigned it to a variable.
00:38Now, before I was just saying it's an object that we created, but it's an instance.
00:42You want to start using that word.
00:44You can use object too when you are talking about it.
00:45That's perfectly fine. It is an object.
00:48But it's an instance of a class, and that's very important for us.
00:51I am going to go into my ruby_sandbox, where I have got a file called classes.rb.
00:57You can either copy the code down or you can pull it from the Exercise Files,
00:59but it's basically just the simple animal class definition that we did earlier
01:03in IRB, but now I have put it into its own file.
01:06Right here is where we are creating the instance.
01:09What gets returned to us from Animal. new as a result of the operation is an
01:13instance, and then we are assigning that instance to animal, and then we tell
01:17that instance to make_noise.
01:19Now, we can do that again.
01:20Let's say down here.
01:22Now we are creating a new instance.
01:23We will call this one animal2 and this one animal1, just so we can tell the difference.
01:27Now we can ask animal2 to do the same thing, animal2.make_noise.
01:32Now, these two instances are going to do the same thing.
01:36Both of them are going to return Moo!
01:37But the important point about instances is that they are not the same, they are
01:41two separate objects, and we will see how to differentiate them a little later
01:44on, but it's important to realize that every time we call Animal.new, we get
01:50back a new and different instance, a different object.
01:54It's a lot like one of those memo pads, like a while you were out pad, and you
01:58can pull off a separate page every time you need to take a new message.
02:02Each one is different, but they all came from the same place.
02:05The memo pad is like the class.
02:07It has all the definitions for it.
02:09It has all those blank spaces filled in.
02:11It predefines how you can take a message.
02:14But then each and every time we pull it off, we make a new instance of it, and
02:19we fill it out differently, with different information for each call.
02:22So how can we fill in the blanks on these forms?
02:25How can we tell our animals apart so that different animals make different
02:28noises, or have different names, or different numbers of legs?
02:31Well, in order to do that we are going to need to put variables inside of our
02:34class definitions to hold those attributes.
02:37Let's look at attributes in the next movie to see how, and then I think it will
02:40be a lot clearer when we are dealing with different instances.
Collapse this transcript
Attributes
00:00Now that we understand about instances, we need to learn about attributes,
00:03because attributes are how we can differentiate between instances.
00:07For example, if we have an instance of our Animal class that we want to be a
00:09pig, and then another one that we want to be a cow, we have to have some
00:13attribute that will give us a way to tell the difference, and tell which one is
00:16the pig and which one is the cow.
00:17If you think back to our Memo Pad example that I gave you earlier, an
00:20attribute would be the blanks on the form that we're going to fill out with different values.
00:24So what we're really talking about when we say attributes, are values that will
00:28persist inside of an instance, and for that we're going to need a variable, and
00:33a variable that can store those values and keep them around inside the instance.
00:37It turns out that Ruby has a variable that's especially designed for just that purpose.
00:41We've seen it before back when we were looking at variable scope.
00:44It's the instance variable, and it's prefixed with the @ sign, just a single @
00:47sign and that's how we know right away that it's an instance variable.
00:51Instance variables are what we're going to use to store the attributes inside of our instances.
00:57You may notice that there's also a class variable right above that.
01:00You may think, well, why don't we use a class variable inside of this class.
01:03We'll get to that a little later on.
01:05Right now, just focus on the instance variable, because that's really what we
01:08want to use inside of the instance of the class, not the class itself, but the
01:12instance of the class, and instance variables are going to allow us to keep
01:16track of attributes.
01:17So let's try adding a noise attribute to our Animal class that's inside
01:22classes.rb, the file we've been working with.
01:25Calling an attribute is just as easy as saying @noise.
01:29That's all there is to.
01:29We're just asking for the value of this variable.
01:32Now the question is how do we set that variable to begin with, so that we can
01:35then return it and make a noise.
01:38Well, we could just simply do Moo, but that doesn't really give us a lot of
01:41flexibility, then all our instances are the same.
01:44It's sort of like having a preprinted memo pad, and every time you pull of a
01:47page, it says that the call was from John Smith.
01:49The call needs to be from different people.
01:51So, we're going to take that away.
01:53Let's try experimenting with setting in a different way.
01:55Let's say animal1.noise = "Moo !", there we go. I'll save that.
02:02Let's try running that.
02:03I'll open up my command line.
02:05Notice that I'm already inside my ruby_ sandbox, and I'll run ruby classes.rb.
02:10You'll see that it returned an error to me.
02:12This error indicates a very important point about Ruby that I cannot stress
02:16enough, which is that you do not -- never, never, never, do you have access to
02:22instance variables from outside of the instance.
02:25They're locked away inside of the instance, on their own, where we can't get to them.
02:30We can't set them, and we can't retrieve them.
02:33Now wait a minute, you're thinking, we can't retrieve it.
02:36That's exactly what we're doing when we say make_noise.
02:38Well, that's because we can access the methods that are inside the class, and
02:43the methods have access to it.
02:45So the scope of an instance variable is inside all of the methods of the
02:50instance, but not outside the instance.
02:52So, if we want to get to those values of the instance variable, we have to do
02:57it by using methods.
02:58It's a very important point.
03:00So instead of doing this line that won't work, instead let's set an instance
03:05that will set it for us.
03:06So let's call it set_noise.
03:09For now, let's just say @noise = "Moo!".
03:13Now this doesn't give us the flexibility that we're looking for just yet, but
03:18we'll get there in one second.
03:19Let's go ahead and just try running this first.
03:21Of course, we'll need to call that method.
03:23So let's say animal1.set_noise.
03:26Let's save it and let's try running that.
03:29So once again here I am.
03:30I'm going to run ruby classes.rb again, and you'll see that it did call it.
03:34Now, notice a couple of things here, first of all, notice that now my two
03:38instances are different.
03:40The first one has a noise of moo, the second one has a noise of nil, because
03:43nothing was ever set, we didn't call set_noise down here.
03:46We just didn't make noise.
03:48So the first point is we can see now we have two separate instances that are different.
03:53The second point is notice that the instance variable persisted inside the
03:59instance, and we still have access to it when we called a different method.
04:04So we set it here, we've retrieved it here. It didn't matter.
04:08It was still around.
04:09We still had access to it, even though they're in two different methods.
04:12Now as I notice, we're still missing that flexibility to make our instances
04:16sort of be whatever we want, but we know how to do that with regular method
04:19calls, set_noise equals to noise, and now @noise can just equal noise, and
04:25there's no conflict.
04:26This is a instance variable, this is a local variable.
04:29They are two different types.
04:30So as far as Ruby is concerned, they are completely different.
04:33They point to two different locations.
04:35There's no conflict there.
04:36So now when we say set_noise, we need to specify, Moo, and then let's go
04:41ahead and do the same thing down here animal2. set_noise, and let's make it equal to Quack.
04:48There we go.
04:48Let's try it saving it.
04:51We'll go back to the Terminal, and we'll run them, and I get back Moo and Quack.
04:55So now we have two different instances with an attribute that we have access to.
05:00In the next couple of movies, I want to explore the idea of how we can get and
05:03set these attributes using methods a little bit further, and show you some
05:06shortcuts that I think will help a lot.
Collapse this transcript
Reader/writer methods
00:00At the end of the last movie, we saw how we could access our instance
00:03variables using methods.
00:05I want to explore that idea a little further in this movie by looking at
00:08reader and writer methods.
00:10Now this is a very common feature of object-oriented programming languages,
00:13sometimes in other languages, they're called getter and setter methods.
00:16Either one is fine.
00:17You can use either name, typically in Ruby, we're going to call them reader
00:20and writer methods.
00:22So, here is the code where we left off inside classes.rb, what we're looking
00:26for is a pairing of something that will set a value for us and something that
00:30will get a value for us, and that's exactly what we already have with our two methods.
00:34The first one is a setter method or a writer method.
00:38So we're setting the value of noise equal to a value, and this is the classic
00:43format for what a setter method would look like, set_noise equal to a value. It sets it for us.
00:48Then we have make_noise.
00:50Typically, we would call this get_noise.
00:52It's a getter method.
00:53We need to change it here when we call it as well.
00:57In either one what do you say, make the noise or get the noise is up to you, but
01:00the idea is that we are getting that value back.
01:03One of these methods sets it, one of them gets it.
01:06Now the important thing about these two methods is that they give us access
01:09control over these instance variables.
01:12So for example, if we were to take away get_noise, now we have no way to
01:16get that value back.
01:18Of course, we could write another method that would do it for us, but our
01:21getter method is gone.
01:23Same thing here, if we were to take away set_noise, now we have no way to set it
01:27by calling a method.
01:29There might be another convoluted way, maybe a back end way that we could
01:32get that value set, but we need a setter method if we want to be able to do it directly.
01:37Now set_ with whatever the attribute name is and get_ is very common in a lot of
01:42programming languages.
01:44In Ruby though, we can make use of that syntactic sugar that we looked at
01:47earlier, and so we can take get _out and simply ask for noise.
01:52So it asks Animal to do the method noise, which returns the instance variable, noise.
01:58It's a very commonsense approach.
02:00So now animal1.noise and animal2. noise just returns that to us, where the
02:05syntactic sugar comes in is that we can do the same thing with set, we can take
02:09away set and just say noise=(noise).
02:14Remember how we did that earlier?
02:15So noise =, and we saw that the parenthesis are optional, we can take away
02:20those, and now it feels just like we're assigning it to a regular variable.
02:26So it feels like we're assigning it to that attribute, but we're not.
02:30We're actually passing it through a method to get to that attribute.
02:34That's a very important difference.
02:36So we get the usage, as if we're just assigning it, but something more complex
02:40is going on behind the scenes.
02:41Now if we didn't have this method, then as we saw earlier, noise= "Moo!"
02:45won't work anymore.
02:47It'll say oops, sorry, I don't have a method called noise =, we have to write that method.
02:52That's our setter method.
02:53So now that we have our class rewritten in the sort of standard way that Ruby
02:57does these reader and writer methods or getter setter methods, let's save it
03:01and just try it out.
03:02I'll go into the Terminal, notice I'm inside my ruby_sandbox, ruby classes.rb,
03:07and it still works exactly as we would expect.
03:09Now some of you are probably thinking, well, that's cool, and I'm glad that I'm
03:12able to just use this = and everything, but are you telling me that every time I
03:16have an attribute, I have to write this pair out?
03:20Well, fortunately not, there is a shortcut, and I'll show you that in the next movie.
Collapse this transcript
Attribute methods
00:00We've seen how we can use reader, writer methods in order to access our attributes.
00:04We saw how we could even use Ruby's syntactic sugar to make the process a little easier.
00:09But one thing that's striking is you may be thinking, well, what if I have a
00:11large class that has lots of attributes?
00:15Are you telling me that I have to go through and write a reader and a writer
00:19attribute for each and every one of those attributes.
00:22Well fortunately, the answer is no, you don't have to do that over and over again.
00:26Ruby provides a very nice shortcut, because this is done so often that we can
00:30just simply use an attribute method.
00:33These are also frequently called attr methods or attr_* methods, and that's
00:40because they all begin with attr_ and that * serves as a wild card for
00:45everything that comes after it.
00:46The three methods that we're going to be looking at are, attribute reader,
00:49attribute writer, and attribute accessor.
00:52Each one of them is actually a method that we're putting into our class.
00:57When that method gets called, it takes a symbol that we provide after it and
01:02turns it into a method for us that we can then use.
01:06So it's exactly the same thing as if we had typed it out the long way.
01:10You can guess what each of them does.
01:12Reader creates a reader method, writer creates a writer method, and accessor
01:16creates both a reader and a writer method.
01:18So for example, attr_reader with the symbol name passed to it as an argument,
01:24will tell your class, hey!
01:26class while you're booting up and getting started, create this definition for
01:30me, create this method that I can then call.
01:32It's exactly the same as if we had typed it out ourselves, exactly the same.
01:37Same thing for attribute writer.
01:39It's the same as if we had typed that same thing we did for noise, if we
01:42had attribute_writer : noise, then it would give us def noise = (value) @noise = value.
01:51And that's exactly what it would create inside the class for us, just by typing
01:55this one simple line, and where that really pays off, of course, is when we want
01:57to be able to read and write.
01:59So attr_accessor creates two methods for us, and saves us a whole lot of typing.
02:05If we want to create more attribute accessor methods, we just put a comma after
02:09the first one and put another symbol and then a comma and so on for all of the
02:13different methods that we wanted to create.
02:15It really is that easy, but it was important that I showed you the long way of
02:19doing it before I showed you the shortcut, so that you would really have an
02:22understanding of what was happening under the hood.
02:24So let's try using these attribute methods.
02:27So in our classes.rb file that we've been working with, I'm not going to
02:31change the class Animal's noise, we already have those methods, I'm not going to replace them.
02:36Let's create some new ones just to see how easy it is.
02:38attr_accessor and then let's make the animal's name, so we'll name our animals,
02:45Tom, Fred,something like that.
02:47Then we could have attribute writer, and let's set the attribute writer equal to
02:53the color of the animal.
02:55Let's say the attribute reader will set equal to the number of legs the
02:59animal has and then arms.
03:01We can put commas so that we could indicate that we have more than one.
03:04So let's stop and realize what it did for us here.
03:06When we first load our class, right, when it first reads in this file, it will
03:11start processing the class.
03:12It will come here and will say, "Ah!
03:14The attr_accessor method.
03:16I need to execute this command."
03:18What it does is creates attribute accessor for a name, which looks pretty much
03:23like what we have here for noise, except with name in place of noise.
03:27So now, we'll have an instance variable called @name that we can access.
03:31We can access it in the same syntactic sugar way that we were accessing noise.
03:35Then once it's done with that, it will come to the attribute writer line and
03:39it'll say, "okay, let's create a writer for color."
03:41So that will create only this one for color, there will not be a method like
03:46this that will allow us to ask for the colored by just saying .color.
03:50Then last of all, it will come to the reader line and say, "Ah!
03:52Let me create a reader for legs and a reader for arms." Not a setter.
03:57There'll be no way to set it.
03:58So let's just try making use of those.
04:00Let's say here with animal1, let's say, animal1.name = Steve, and then let's ask
04:08it to puts animal1.name so that it will output it.
04:13So we should have been able to write to it, and to read from it with those two steps.
04:17Let's try doing animal1.color = "black ", and then let's do puts animal1.color.
04:29Now we should be able to write to it, but not read from this, so we're expecting
04:32an error there already.
04:35Then let's try last of all animal1., and we'll just do legs = 4, and
04:42animal1.legs, we'll need a puts in front of that. There we are.
04:48So that should return these values to us, but we're going to get a couple of
04:50errors, because we're trying to read and write when we shouldn't be allowed to.
04:53So let's just see how far we get.
04:55Let's go into the command line, notice that I'm already inside my Ruby sandbox
04:59and I'll run ruby classes.rb, and sure enough, undefined method color.
05:04So the method color doesn't exist.
05:06It did, notice, come back and report Steve, first.
05:11But then it got to here and it said, no, sorry, I do not have this method.
05:15It didn't complain here.
05:16It has that method.
05:17It didn't have the reader method.
05:19Now we could put our own in.
05:21Let's just do that, def color, and let's return @color.
05:26Maybe we want to do something a different though, maybe we want to say return,
05:31The color is, something like that.
05:37Now let's run it, we'll still get an error later on, but we'll get a little further.
05:41Now we get, The color is black, so now we get undefined method legs=, because we
05:47did not allow it to be a writer.
05:48It's just a reader.
05:50So we need another way to set the legs.
05:52Let's say that we have something here.
05:54Let's create another method at the beginning called def, and setup_limbs, we'll call it.
06:00When we set up limbs, we're going to say, well, legs should be equal to 4, and
06:06arms is going to be equal to 0.
06:08So let's just try running that real quick, we'll need to run that setup.
06:12Let's do it right here, animal1. setup_limbs, and let's run it.
06:21Now we get -- oops, sorry, we still have that legs=, we've got to take that out
06:24of there, because that won't work.
06:26We can't set it anymore, but now we can still read it back. Let's try that.
06:31Undefined local, puts animal1, that's my mistake, little typo. There we go.
06:36So now everything returns to us.
06:40So take a moment and look at what we did there.
06:43We used these attribute accessors, writers and readers, to make these
06:47definitions for us much easier.
06:49We can still define it ourselves, we can do something different when we define
06:53it, or we can still have access to those through other methods, but it's just
06:57the simple access that we'd lose, right, we don't have that direct access to
07:01them unless we write something for ourselves or use these attribute methods.
07:07Because creating these kinds of attributes that have access control is done so
07:11commonly, Ruby provides this very handy shortcut for us.
Collapse this transcript
Initialize method
00:00Very often in Ruby when we create an instance of a class, we want that instance
00:04to do some initialization, settings some default values or calling some default
00:08methods that will happen right at the beginning.
00:11We saw a little bit of this in our last movie, when we wrote the set_limbs
00:15method, and that was a method that we called that set the values of the legs and
00:20arms, instance variables on our animals so that they had a default value there.
00:24Well, instead of calling a separate method that will set those up, let's instead
00:27use the initialize method.
00:28So here I'm in the Animal class that I've been working with.
00:32Creating an initialize method is just as easy as calling initialize.
00:36That's all there is to it.
00:37Now I no longer have to call setup_limbs, boom! Done!
00:41It's just like that. That simple.
00:42Now initialize will set any values that I want here.
00:46It will also allow me to execute some other Ruby code, I can call other things in here.
00:51Maybe I want to output something.
00:53Let's try puts "A new animal has been instantiated".
00:59That's a fancy word for saying we created an instance of it that has been
01:03instantiated, a new animal has been instantiated.
01:06Let's go into the command line, you'll notice that I'm already inside my Ruby
01:10sandbox, and I'll just run ruby classes on it.
01:14There we are, A new animal has been instantiated, right?
01:18So it both sets values, but also calls any Ruby code that we want to put in there.
01:22So that can be any number of things, but every time an instance of this class is
01:26created, do these initialization routines.
01:29Now notice that we never call initialize explicitly, initialize is sort of a
01:33magic method name that happens automatically on every object.
01:38So when we call Animal.new, the new method creates it, but the first thing that
01:44does upon creating it is run this initialize method.
01:47Now initialize, like all methods also allows us to pass in arguments to it.
01:52So let's say, for example, legs, arms, and actually let's go ahead while we're
01:57at it, and let's put noise at the beginning.
02:00Well now, we have access to legs and arms, and while we're at it, let's go ahead
02:05and set @noise = noise.
02:08So it works exactly like a regular method, there is nothing special there, but
02:11how do we pass these values into initialize?
02:15Well, it turns out that the new method takes values and passes them right
02:21on into initialize.
02:22As soon as it creates the new object, it passes initialize, whatever values it has.
02:26So we could for example, say, Moo is the noise, and legs, and arms, 4, and 0.
02:32So now we no longer have to set noise, and we never set legs that was being set
02:38before in the methods. So let's try that.
02:40Let's go back and run ruby classes.
02:43You'll notice that now, I'm getting a wrong number of arguments error.
02:47That's on my second animal, because once we start adding arguments to new, it
02:52always expects them, unless we set some default values.
02:55We saw that before with methods, there is nothing really new there.
02:57But let's just do Quack, there we are, so we don't have to set this anymore.
03:02Now for legs, let's set the default equal to 4, and the arms, the default, equal to 0.
03:07So now we don't have to pass those values if we don't want to.
03:11When we run it, everything works exactly like we would expect.
03:14So that's all there really is to using initialize.
03:17It works just like a normal method, the only difference is that it gets called
03:20automatically, and that values we pass into new, get passed on to initialize.
Collapse this transcript
Class methods
00:00So far we've been creating instances of our classes, and then we've been calling
00:04methods on that instance.
00:06We can also call methods directly on the class itself, and we call those class methods.
00:11The other ones of course are called instance methods.
00:13So in this movie we're going to look at how we can create our own class methods.
00:17We've already seen how to call a class method, even though we didn't know it,
00:20and that was Animal.new.
00:22New is a class method.
00:24It's a built-in class method to every Ruby object.
00:28So, we can call new, and it returns a new instance to us.
00:31But it's still a method.
00:32It's a method that exists on the class even when we don't have an instance, and
00:38that's what you are going to use class methods for.
00:40We are going to use a class method when we want the class, to do something for us.
00:44Even though there may not be an instance in sight.
00:46It doesn't matter, maybe there are instances, maybe there aren't.Defining class
00:49methods is very simple.
00:51We do it just the same way we do instance methods except that we put the self
00:55keyword in front of it.
00:56So, self.method_name let's us know that that is a class method.
01:01It's something that our class itself will execute.
01:04Now the self keyword in Ruby applies to whatever object we're currently in.
01:09So, in this case, where we're in the definition of the class, self is the class itself.
01:15If that still sounds very abstract and hard to get your head around, I think
01:18it'll be easier once we actually try a couple of examples.
01:21So, let's start by adding a class method to our Animal class, in the classes.rb
01:27file we've been working with.
01:28I am going to do that above initialize, this is mostly by convention.
01:31You can put it anywhere in the file you want, but typically you'll put the class
01:35methods above the instance methods.
01:37So, def self and let's create one called all_species, just like we were talking
01:42about, and this will return a list of all possible species that this class knows
01:47about, obviously not all species that exist.
01:50And I am just going to paste in an array there,
01:54 [cat, cow, dog, duck, horse, and pig].
01:54So, when we ask the class, hey!
01:57Tell me about all the species that are there.
01:59It doesn't have to have an instance, it already, the class itself can tell
02:03us that information.
02:04We don't have to create an instance in order to get to it.
02:06So, let's just save it. Let's try it.
02:08Before we even get to an instance down here, let's just do puts, and we will ask
02:12the Animal class for all_species, right?
02:17This will put out an array.
02:19Let's go ahead and do an inspect on the end of the array too, just so that it
02:22outputs it in a little nicer format for us to read.
02:24So, let's switch in our command line, notice I am already inside my
02:28ruby_sandbox, ruby classes.rb, and there we are.
02:33Just see that it outputs the array.
02:35So, there are three important things to notice there.
02:38The first is that we didn't have an instance when we called it, the second is
02:43that the way we called it, which is to call it directly on the class, and the
02:46third, was that the kind of information that we returned was general information
02:51about the class itself.
02:53Now as I noted earlier, new is an example of another class method.
02:57We can create our own class methods that do things for us instead of just
03:01returning information.
03:02So, let's add another method, this one will actually do something instead of
03:06just returning information, let's say a def self create_with_attributes, and
03:14the attributes we are going to pass are going to be the noise that it should
03:17make and the color.
03:20And then all we are going to do is create a new class, right?
03:24Create an instance of the class, and then make sure that it has these attributes
03:29before we return it to the user.
03:31So, we'll still need to create one Animal.new, and you'll remember when we
03:36created new, now we need to provide a noise.
03:39That's a required attribute.
03:41So we'll pass in noise, and let's go ahead and capture that as a local variable.
03:46Animal =, and then we could set, animal.color, because we set attr_writer to color up here.
03:53So, we can write to color and we will set it equal to color, and then last of
03:57all, we'll return the Animal object itself.
04:00So, we are going to return the actual animal instance, so we are calling a
04:03class method, just like new, but what happens in the end is it returns an
04:08instance of it to us.
04:10So, we'll try this out, before we do it, I just want to point out one more thing
04:13which is that I am calling Animal.new here, because I am inside the class, I can
04:18also make use of self.
04:19Once again, the keyword refers to the object that we are in.
04:22It's not only for use in defining our methods, we can make use of it
04:26throughout the method.
04:28Let's drop-down, and let's try this create with attributes.
04:31Let's just do it to animal2 here.
04:33Let's try create_with_attributes, and now in addition to Quack!
04:39I just need to tell it white, and then puts animal to noise, and the very last
04:44thing we puts animal color, right?
04:48And I have a method here that will report the color to me.
04:51So, let's try that out.
04:53ruby_classes.rb, and there we go.
04:55We are getting the Quack!
04:56and we are getting the color as white.
04:58So, both are being set by our new create with attributes method.
05:02So, hopefully now you see not only the mechanics of how to work with class
05:06methods, because I think that's pretty easy, but also conceptually, when you
05:10would use it, I think that might be a little bit harder.
05:12It's things that are at the class level that do not have to have an instance
05:16around, things that are more general than a specific case.
Collapse this transcript
Class attributes
00:00So far we've seen how we can create methods on our instances, and those are
00:04called instance methods.
00:05We've seen how we can create methods on our classes, and those are called class methods.
00:09We also saw how we could put attributes on our instances.
00:12It would store values that were particular to the instance.
00:16In this movie, we are going to take a look at class attributes, which are the
00:19same thing, but attached to our classes.
00:22That is, they are for storing values that apply to the class generally.
00:26The same way that the class methods apply to the class generally.
00:30And the way that we'll store these values is going to be in a class variable.
00:34We took a peek at this before, when we were looking at instance variables.
00:37It's in the line right above it with two @ signs in front it.
00:40So, if you see the two @ signs, it's a class variable and it will persist
00:44anytime we have the class, even if we don't have an instance.
00:48Instance variables are going to be only inside of the instance.
00:52That's the only time we'll have those.
00:53Let's see how we can use class variables.
00:56Finding a class variable is very simple, we just simply use @@ and let's say species =.
01:02That is now the class variable.
01:05It will persist anytime we have the class.
01:08Now the one problem with this is that this doesn't get defined unless we call
01:13this method all_species, right?
01:14We don't have an initialize method, like we do with a class or we could do
01:18this when it boots up.
01:20Instead what we do, if we want it to happen automatically, as we put it in the
01:24body of the class, then it happens when the class is defined.
01:28So, the initialization of the class is when it gets read in.
01:32So, the Processor starts reading in the file and it says, "Ah!
01:35I am going to create a class, I am going to call it animal, I am going to create
01:38an attr_accessor, a writer, and a reader, and I am going to set the class
01:42variable species equal to this array.
01:45Then I am going to set up these definitions for what I'll do inside the class
01:49and inside my instances" and so on.
01:51So this is the way that we define class methods that we want to exist from the
01:54beginning, all right?
01:55It's the same as putting them in the initialize method for an instance.
01:59So now if we want to retrieve that value with all_species, we just say
02:03@@species, and that will now pull back that value that was already set, we don't
02:08have to even have an instance. Let's try it out.
02:11Notice down here, I've already got the call to all_species, right?
02:14puts Animal.all_species, I don't have an Instance at this point, but first
02:18Instance gets created here.
02:20So, we're looking up here where we don't even have an Instance.
02:23Let's open up the command line, notice that I am already inside ruby_sandbox,
02:27ruby_classes.rb, there we go.
02:30It still pulls up those values.
02:32That is now being stored in a class variable which is also known as a class attribute.
02:37Now this is certainly a perfectly appropriate time to use a class variable,
02:42because we are using it for information which is general for the whole class, so
02:46then we have the ability to say oh!
02:48When we are creating a new Instance maybe, maybe we want to make sure that it's
02:52one of these species.
02:53That's a possibility.
02:55We can now check that against our @@species variable.
02:58Another very common use case is if we want to keep track of things.
03:02Let's say we have @@total_animals, very common usage, total_animals = 0.
03:08And then whenever we initialize a new animal, all we have to do is say oh!
03:12By the way, while you are initializing it, let's take @animals and do += 1.
03:17Now the number of animals increases every time we create one, so we can keep
03:21track of how many animals have been created.
03:23That's one way to do it.
03:25Another great use of class methods is not just to keep track of the number of
03:28animals but to actually keep track of the instances themselves.
03:31So, let's say here we make this instead current_animals.
03:35So, if the animals that have been instantiated, the ones that have been created
03:38and instead of being 0, it's going to be an empty array.
03:42So, now down here we'll say well, current animals should instead be appended the value self.
03:50In this case self is an Instance, it's the instance that's just been created
03:55and that keyword will plug that object not the class, remember self is a magic
03:59word for the object.
04:00It's inside at that moment.
04:01But this time, it's going to be the Instance.
04:04Up here, when we used it, it was the class.
04:05So, we are using it for an Instance and saying put this Instance inside the
04:09current animals array, so we can keep track of it.
04:12So, let's drop down here to the bottom and we'll put, puts Animal to class, and
04:18now we want to ask it for its current_animals.
04:22That's what we want to ask it to return is the current_animals.
04:25Let's go ahead and put inspect on it.
04:27So, we can see what that array is going to look like in a nice friendly way.
04:29So, let's try that out and let me give you a hint this is not going to work.
04:33We've done ruby_classes, at the end undefined method, current_animals.
04:37Now that's because the same thing is true with our class attributes and class
04:42variables as was true with our Instances.
04:45We cannot access those values, those attributes from outside the class.
04:50In order to do that, we need Reader and Writer methods.
04:54Let's see those in the next movie.
Collapse this transcript
Class reader/writer methods
00:00We saw how instance attributes used Reader Writer methods to give access to them
00:04from outside of the instance.
00:06Now in this movie we are going to see how we can use Class Reader/Writer methods
00:10in order to get access to our class attributes from outside of the class.
00:15So I am still inside the classes. rb document we've been working with
00:18throughout this chapter, and in the last movie we tried to call the current
00:21animals method on animal, right?
00:24And we can't do that because we don't have a current animals method.
00:27We have a current animals attribute, right?
00:30A class variable that we set, but we don't have a method to be able to read it.
00:34Well writing that method is trivial, right?
00:36We know how to do that, self.current animals.
00:40And then what should it return?
00:42It should return current animals.
00:45That's all there is to being able to create a Reader method for this that will
00:49let us return that value.
00:50In fact we had already done that here with all species.
00:53We could just simply shorten this to species and then it kind of fits more with
00:57the typical Ruby style of giving us a little bit of syntactic sugar.
01:01In fact we could have a Writer method, def self.species=, and then let's ask it
01:08to provide an array and we will give it a default value of an empty array.
01:13And then, of course that's going to take @species and it's going to set it equal
01:18to the array that we've asked it to send out.
01:21So now just like we had for the Reader/Writer methods we created for our
01:25instance methods, we have the same thing here for our classes.
01:29Species is the Reader, species= is the Writer.
01:32The only difference is that we are saying it's a class method and it's a class
01:37variable being returned.
01:38Otherwise it's exactly the same thing as what we had before.
01:41Let's go ahead and just prove to ourselves that worked.
01:43I am down here before we asked for species, we'll need to change this from all
01:47species to just species, right?
01:48or that will break.
01:50Let's set that value, let's say Animal, tuck in the class directly, species=,
01:56and let's throw in a couple of species here.
01:57Let's say frog and fish.
02:01So it's just something that's very different than what we had before.
02:03Now we'll just go back into our command line.
02:06Notice that I am already in my ruby_ sandbox, ruby classes.rb, there we go.
02:11Now the value of species has been set.
02:14So I will set it to something different and I read it back.
02:17I use my Reader/Writer attribute on it.
02:18You'll also notice that the other request you made down here at the end, for
02:22current animals, one we were trying to do in the last movie that also works now
02:26as well because I created a Reader method for it.
02:29So now it returned to objects for us.
02:32What we are seeing here is a summary of the way that it tries to represent an
02:36object as text, right an object is not text.
02:39But it tries to give us something that sort of looks like it.
02:41It shows us what all those instance variables inside there are.
02:44So we've got the first animal which has color black name Steve, noise is Moo,
02:49the second animal color white, noise equals Quack! and so on.
02:53So we've got those two objects inside of our array.
02:55We can also apply the Each method to it instead of inspecting it.
02:59We saw how to use the Each iterator to loop through each of those items one at a
03:03time and then we could ask it for its color, or its sound, or something like
03:06that, and so that will tell us then all the current animals.
03:10It will keep track of the inventory for us.
03:12So that's really all there is to creating these class methods that are
03:15Readers and Writers.
03:16The one thing though is that we had before this attr_writer and we had
03:22attr_reader and attr_accessor.
03:25We don't have anything like that at the moment in Ruby.
03:28That may be something that comes in a future version, some kind of a
03:31convenience method for that.
03:32Right now you have to write it yourself, which isn't as big of a problem,
03:36because these happen a lot less often than the other kinds of attributes.
03:39The other ones happen very frequently so we need the shortcuts.
03:42For the class ones you'll have to write them out yourself or you could create
03:46your own method that would do that for you.
03:49In Ruby on Rails, for example they've created one called cattr_accessor.
03:54So you can make use of it if you are using Ruby on Rails you can get access
03:58using the cattr_accessor.
04:01But that's something that doesn't exist in the core Ruby currently.
04:04It's something that was added on.
Collapse this transcript
Inheritance
00:00In this movie we're going to talk about class inheritance.
00:03Now this is not the same as inheritance in the real world where you inherit
00:07money and objects and things like that from your ancestors, instead in
00:11object-oriented programming inheritance refers to inheriting the methods and the
00:15attributes of another class.
00:17It's a very common feature in almost all aspects of object-oriented programming
00:21and Ruby is no different.
00:23Let's say for example that we have our Animal class that we have been working with.
00:26Up until now we've been creating instances of that Animal class.
00:29We can create several instances and then we can give attributes to
00:33those instances, right?
00:34Cow, pig, and duck, we can give them sounds.
00:36Well, instead of doing that we could also have the ability to create
00:40subclasses, classes that would inherit information from animal which would be
00:45their own unique class.
00:47So instead we can have the animal class and create a new class called cow, and
00:52that cow class would inherit all of the behaviors of the animal class, but it
00:57would be its own class at the same time.
00:59We could also create another one called pig and another class called duck.
01:02All of these would inherit from animal but each would be its own class.
01:05They could have its own unique behaviors separate from the animal class, even
01:09though they sort of come from the same route.
01:11We call the parent class animal, the Superclass or you can just call it the
01:16Parent informally, but technically it's the Superclass, and these other ones are
01:19the Subclasses and we call those the Children informally.
01:23So we talk about the parent and child relationship a lot of time between two
01:26different classes, what we are really talking about is the superclass and the subclass.
01:30And then from these classes we could create our instances, we could have a Cow
01:33instance and give it the attribute Moo for its noise.
01:37We could do the same thing for pig, make it Oink and Duck would be Quack.
01:40So we would end up with in the end are still three instances.
01:43But there are three instances that might have very different behaviors.
01:48For example, a duck might have a whole bunch of methods related to being able to
01:52swim, but a cow doesn't need to have those methods.
01:55A cow might have a lot of methods about how to graze for grass, but the duck
01:59doesn't necessarily need those methods.
02:01But at the same time all of them could inherit some common attributes, from
02:06animal, like the fact that they have legs, like the fact that they make a noise,
02:10those would be inherited.
02:11I think I have illustrated it enough.
02:13Let's try to put into practice.
02:14I am still in my classes.rb file that I have been working with.
02:18I am going to use a feature of Textmate here to just fold up some of these
02:21methods that we've been working with.
02:23It's kind of a nice feature that Textmate just kind of let you get things out of your way.
02:26So that's what I am doing here.
02:27If you are not using Textmate that's fine.
02:29It just clears up my screen a little bit and gives me a little more room.
02:31I am going to just create a new class and we are just going to call this class Cow.
02:36The way we indicate that it is a subclass of the animal parent class is with
02:41the less than sign, and then the name of the parent class, and you'll notice
02:45that it gives me a nice italicized thing there in Textmate to let me know that
02:49that's what's happening.
02:50So, the cow class inheriting from animal.
02:54That's all we've got so far.
02:55Let's just try with only that.
02:58Let's try to drop down here at the very bottom after we've done all this stuff
03:01that we've already been working with.
03:02Let's do a new one.
03:03Let's say maisie, the cow, is going to be Cow.new.
03:08Let's just try that out, see what happens, if we just try and create a new
03:12instance of our class Cow.
03:14Let's go to our command line.
03:16Notice I am already in my ruby_sandbox, ruby classes.rb.
03:21So it goes through and it does everything as we would expect.
03:23And then right here it says, "woop, wait a minute.
03:25Initialize wrong number of arguments.
03:28You sent 0 and I was expecting 1."
03:30Well, that's because it inherited this initialize method.
03:35Initialize is expecting us to pass in a noise. So let's try that.
03:39Let's try passing in a noise when we create it.
03:41So the noise will be Moo!
03:43And then let's go ahead while we are down here, and let's say well, let's puts maisie.noise.
03:49Let's ask what Maisie's noise is?
03:50So let's go back ruby classes, we'll run one more time.
03:54This time it works.
03:55You'll see a new animal has been instantiated.
03:58That's happening in that Animal parent class, but we inherited that into the Cow
04:03class, and then it comes back with Moo!
04:05So, it did successfully created.
04:07It created it using this initialize method and we were able to use this noise
04:12method to return a value all just by sub-classing Cow from Animal.
04:18Now there is a difference here, right, if we were to say do say puts
04:22animal1.class and puts maisie.class.
04:28Then we'll actually see those class names.
04:30Let's run that one more time. Oops!
04:31Sorry I mis-spelled maisie, and let's try that again, maisie, there we are.
04:38Now it comes back and it tells us, aw!
04:39one is an animal and another one is a cow.
04:41Now we can actually tell the difference.
04:43Now we have the ability to know is this thing I am working with a cow, we don't
04:47have to give it an attribute of cow it can be the class cow and have different
04:52behaviors that we can add on.
04:53We could just as easily go in and start adding new features to our cow class
04:58that would exist only in cow.
05:00They would not be in animal.
05:01So we get everything that was in animal, plus anything we define inside cow.
05:06And that's really all there is to the fundamentals of creating Inheritance.
05:09It's a good way to help organize your code, but there are also some very
05:12powerful things that we can do when we start borrowing features from other classes.
05:17The one last note I want to make on this is that unlike a lot of object-oriented
05:20languages, we cannot have multiple inheritance.
05:24In Ruby we can inherit from one and only one superclass, right, not
05:28multiple, only one each time.
05:31If you want to have different behaviors we'll use modules for that, we'll talk
05:34about that in the next chapter.
05:35So I just want to make a footnote, if you are used to working with other
05:37languages that use multiple inheritance, here you can only inherit from one class.
Collapse this transcript
Subclass overriding
00:00In the last movie we saw how we could inherit all of the methods and attributes
00:05from a parent superclass into the child subclass.
00:10But what about, when you don't want to take all of the methods?
00:12Let's say you want everything that's in the parent class except there are a
00:16couple of things you want to do differently than the parent did them.
00:19Well, we can do that by overriding methods in the subclass.
00:22So here I am in the same classes.rb file we've been working with throughout the
00:26chapter and I've got class Animal and then I've created a subclass of Cow, which
00:31doesn't have any attributes or methods in it.
00:33It's inheriting all of its methods and all of its attributes from the Animal class.
00:37Now, let's take a look here at color.
00:40Right now we have a method inside our Animal class called Color.
00:43The color is blank.
00:45Let's try and access that.
00:46Down here we'd already created an instance of the Cow called maisie.
00:50Let's drop down one more line here and let's say puts maisie.color, all right.
00:55So we'll save that.
00:57Let's just run it and see what we get to start with.
00:59So I am inside my ruby_sandbox already, we'll run ruby classes.rb.
01:04The color is nothing, so it hasn't been set.
01:06We need to set Maisie's color first.
01:09We can see that one of the ways we can set it is using create with attributes
01:13when we create it, right, that allow us to set the color.
01:15So let's try that instead.
01:17Let's try now using Cow create with attributes.
01:20We still have this method that's available to us because it came from the
01:23parent class, and now let's create the color, and let's say that Maisie is a yellow cow.
01:28All right, so yellow cow will save it.
01:31Now let's just try running it one more time, ruby classes, the color is yellow.
01:35So now Maisie has the color yellow.
01:38So now let's see how we could override this behavior.
01:40Now that we see what it does by default, it's real easy.
01:43We just simply write def color, and then whatever we want our new thing to be.
01:48So let's say The cow's color is.
01:52We'll do the exact same thing, but now it's going to tell us that it's a cow.
01:56So that's something that would be in the Cow class, and the animal class would
01:59just say the color is whatever it is, but the cow knows that it's a cow.
02:03Let's try it one more time. There it is.
02:06The cow's color is yellow.
02:07So now we've overridden it.
02:09Now it didn't change up here for these other animals we created where we created
02:12something from the Animal class directly, we just have the colors white.
02:16All we did was say inherit all the behaviors of animal, but after you do that
02:22overwrite the Cow class with this one method, it really is that easy.
02:26The reason why this works is because Ruby reads in the class
02:29definition sequentially.
02:30So the first thing it does is it makes the inheritance, then it redefines color.
02:35Now we can redefine things as often as we want, right, redefine color.
02:40We could say my color is and then do the color, right?
02:43Let's just save that, go back to our command line.
02:49My color is yellow.
02:50It didn't object to the fact that we had more than one method this one got overwritten.
02:54This might as well not exist at all because we not only overwrote the parent
03:00superclass, we overwrote our own method a second time.
03:04So it's no problem, Ruby doesn't mind us having more than one but whatever the
03:07last definition is that's the one that wins.
03:10That's the one they got assigned and kept inside the class.
03:13The fact that Ruby lets you override these methods is actually one of the
03:16really cool features of Ruby because we could override any class method in exactly this way.
03:21Let me show you what I mean.
03:21Let's go back to our command line.
03:23I am going to open up a new irb session with simple prompt.
03:26So we've gone back in irb.
03:28Let's just create a simple array, x=1, 2, 3.
03:33Now if we ask it to turn that array into a string, x. to s, we get back 1, 2, 3.
03:40That's what the two-string method does for an array.
03:42It just smashes everything together.
03:44Well, let's just say we don't like that behavior, we'd like to do something
03:47a little different.
03:48All we have to do is open up class array.
03:51Now this is the Ruby class array, we are changing the behavior of a fundamental
03:55Ruby class, we have the ability to do that.
03:58And then let's redefine it, def to_ s, and now it can be whatever new
04:03definition we want.
04:04I am going to say self.join and then, space and then we'll need to end and end.
04:12Now we've changed the definition of this one method, everything else about class
04:17array is still the same.
04:18It was already defined.
04:19What we did essentially was reopen the class.
04:22Just for a second, make a new definition, and it went ahead and put that into
04:26that previous class definition that was there.
04:28It's not the same thing as a superclass and a subclass, but we are overriding
04:32the existing method.
04:33And now let's just try it again.
04:35We'll just go up to the array x.to string, and now I get this new behavior.
04:40I think that's a very powerful feature of Ruby, the fact that we have the
04:43ability to override methods, not just in parent classes and subclasses, but any
04:48class method we want.
04:49At any time, we can stop and override it including the Ruby Core Library, and
04:54that's a really powerful feature.
Collapse this transcript
Accessing the superclass
00:00In the last movie we saw how we could override some of the methods that are
00:03subclass inherited from its superclass.
00:06But sometimes we don't want to override the method entirely.
00:09We want to still take in most of that behavior from the parent class, but we
00:13just want to tinker around the edges a little bit.
00:15Well, we can do that, thanks to the keyword Super, and that's how we'll access
00:19the superclass from the subclass.
00:22So I've already got my class Animal that we've been working with and I created a
00:25subclass called Cow.
00:27Let's create another subclass now.
00:29Let's call it subclass Pig.
00:31That will be subclass of Animal so it will inherit all those behaviors from
00:35Animal, but let's override something inside of it.
00:37Let's say we'll take the noise method that we've been working with.
00:40So it normally just returns noise.
00:42Let's override that.
00:43def noise, and we've seen how to do basic overriding.
00:46Let's say Hello, right, so that's just going to return Hello instead of whatever
00:51the animal's noise is.
00:52Let's go ahead and instantiate it down here.
00:54Let's say wilbur is going to be equal to Pig.new, and we know that we need to
01:00provide something to the initialize method, so that's going to be just Oink!
01:04So now it will have a noise but then when we say puts wilbur.noise, it will
01:12return to us, Hello.
01:13Let's go to our Terminal and try it, ruby classes, notice I am already in my ruby_sandbox.
01:19So there we are, we just get back Hello, we didn't get back Oink!
01:22we overrode it successfully.
01:23We've seen how to do that.
01:25Now though if we want to call what was in the parent method, all we have to do is put super.
01:30So let's go ahead and just comment out Hello for now, and we will just have that
01:34super method in there so we can see what it does.
01:36So let's run it again, Oink!
01:40So effectively in this case I did not override it.
01:43I started to override it, and then I said, oh -- and by the way Super means do
01:48whatever the parent was going to do, call the noise instance on the parent.
01:53Go find that and do that original version.
01:56That's what super does.
01:57Now let's swap this around for a second and let's just say we call super
02:01and then we call Hello.
02:03Now think about what you think this is going to do before we do it.
02:06I'll save it and let's go back and let's run it one more time and we just get
02:11Hello, we don't get the Oink!
02:13And I want to make sure that you understand why.
02:15Super calls this parent method, right, I am just going to fold up Cow here so
02:19it's out of our way.
02:20It calls this which returns the value at noise.
02:23So this returns at noise to this function, okay, doesn't get returned back to
02:30where we called this noise method.
02:33It just returns it here.
02:34Then the next thing we do is Hello, which is the same thing as return Hello.
02:39Now if we were instead to do something like parent_noise = super, and then we
02:47said Hello and also, and then we did parent_noise.
02:53Now it will return both of them to us.
02:56So super is just a method.
02:58That's all it is, and it can return a value, but it doesn't automatically return
03:03it back as this return value here.
03:05We still have to return at the end of it.
03:06So I just want to make sure that's clear.
03:08Let's try that out, Hello and also Oink!
03:12That's all there is to being able to access these parent methods is this keyword
03:16super, but just make sure that you understand what it's doing.
03:19It's actually calling that method, and then it's just as if we called any other
03:23method, we still have to work it in the same way here.
03:25So it doesn't matter if we call it before we do something or after we do something.
03:28It's just simply a method call.
Collapse this transcript
7. Modules
Namespacing
00:00In this chapter we will be taking a look at Ruby's modules.
00:03Put it simply, modules are wrappers around our Ruby code.
00:07Now, you may be thinking, wait a minute, isn't that what a class was?
00:10A class was a way for us to roll up different methods and attributes into a wrapper.
00:14Well, modules work in a very similar way, but modules have one important
00:18difference from classes.
00:20They can't be instantiated.
00:21We can never have an instance of a module the way that we have an instance of the class.
00:26Instead, we are going to use our modules in conjunction with our classes.
00:29That will make more sense as we examine the two reasons why we would want to use modules.
00:33We will look at the first one in this movie, which is namespaces.
00:37If you come from another programming language, you may already have
00:39familiarity with namespacing.
00:41It's a very common concept.
00:43If not, imagine that you have a classroom that has two students in it named Sophia.
00:47The teacher would end up calling one of them Sophia M. and the other one Sophia
00:51S., so that she could tell them apart, and that way she could address questions
00:54to the right Sophia and not just simply say Sophia and have both of them try and
00:58answer at the same time.
00:59Well in Ruby, in the same way, namespaces allow us to have class names which
01:05don't conflict, so that we can tell the class names apart.
01:07Let me give you a concrete real-world illustration.
01:11Let's suppose for a moment that we have developed a website for online dating.
01:14So our users are going to login, they are going to fill out personal
01:16information, and then they will get matched with people that they might want to date.
01:20Well, in the process of building that site, we might need a class called Date,
01:23which would set up the meetings between the two people.
01:25But our usage of Date is very different from the standard Ruby definition, which
01:29is a calendar date, a year, a month, and a day.
01:32Now, if they have the same name, we will have a conflict, because Ruby won't be
01:35able to tell them apart.
01:36For example, we would have dinner equals date new and we would be talking about
01:40this meeting that should happen, but then when we try and say on what calendar
01:43date it ought to happen, we would be saying dinner.date = Date.new.
01:47Ruby can't tell those two things apart.
01:49To avoid this name conflict, we can use a module to namespace our date.
01:52All we have to do is wrap our class in a module name.
01:56So here you can see I have put the module Romantic around the class.
02:00Romantic is still capitalized and everything is exactly the way a class name
02:03would be, but it's a wrapper around our class.
02:06Now when we want to get a new instance of our date for our dating site, we use a new notation.
02:12Now we say dinner = Romantic::
02:16Date, and that tells it that we are talking about this namespaced date.
02:20The one that belongs inside the Romantic module, that is kept completely
02:24separate from the dinner.date = Date.new.
02:29Now it knows that's Ruby's internal date.
02:32Modules are named exactly the same way that classes are.
02:34It's just a wrapper that goes around it.
02:36So module Romantic is the example I have given.
02:39We can make that anything we want.
02:40That double colon lets you know that it's been namespaced.
02:43So we are not just talking about the standard date, we are talking about date
02:46within the namespace Romantic.
02:49Namespacing really is that easy.
02:51Now, I don't want you to think that namespacing is only to keep you from
02:55conflicting your classes with Ruby's classes.
02:58It could be to keep it from conflicting with another class that you have written
03:01inside the same site.
03:02There might be two different contexts where we need to use a certain class name.
03:06One very common use of namespacing is if we were going to try and release
03:10our classes out as open source, so that other people could use them in their projects.
03:15We can't anticipate ahead of time what their class names will be, so to make
03:19sure that our classes don't conflict with whatever they have got, we would
03:22namespace them and we might wrap them in a module that had some kind of unique name.
03:26Maybe our name or our project's name or something like that, so that we could
03:30make sure that it always stayed separate and didn't conflict with whatever they already had.
03:33I think that's enough on namespacing to make the point.
03:36Let's take a look at the second more powerful use of modules, which is as Mix-ins.
Collapse this transcript
Mixins
00:00In the last movie we saw how to use modules for namespacing.
00:04In this movie we are going to look at the second more powerful use of modules,
00:06which is to use them as mix-ins.
00:08Let me explain what the term mix-ins means.
00:10Unlike some other programming languages, Ruby doesn't let us have
00:14multiple inheritance.
00:15If we have a class, that class can inherit its behaviors from only one parent or superclass.
00:21That's it, just one.
00:22If we need additional functionality to be brought in that's shared among
00:26classes, we will need to put it in a module, and then we can take that module
00:29and all its functionality and mix it in to any class that needs it.
00:33It's a very powerful way for us to keep our code organized.
00:36In my ruby_sandbox I have now got a file called person.rb that I created.
00:41It's a very simple class for person.
00:43It has some attributes.
00:44It has a couple of methods that work with those attributes, nothing that we
00:48haven't seen before.
00:49Now, if you are like me, you frequently end up with a case like this, where
00:52you have class Person.
00:53But then you want to say, oh, well, I also need a class Teacher, and maybe
00:58let's also have a class Student, and we end up with all these different classes
01:02which are very similar.
01:03We want the full name method to be in all three of them.
01:05Now, we could just copy it three times, and with something as simple as the full
01:09name method, that's not a terrible choice, but if it was a really complex
01:12method, that would be a really bad choice.
01:15So instead what we want to be able to do is use modules as mix-ins for this behavior.
01:20So let's create a new module up here.
01:22Now, this is not going to wrap around our class.
01:24It's going to be a standalone module.
01:26module ContactInfo.
01:28Notice I did CamelCase here, just like a class name.
01:31Now, as I said at the beginning of this chapter, this module is just a wrapper for code.
01:36So let's take all of this functionality, every single bit of it, and let's just
01:40cut it out of our Person class and put it into our module class.
01:43So now our class is no longer wrapping all that functionality, the module is.
01:48Well, that's great, except now we need a way to get the module and all its
01:52functionality into our class, and we do that with the Include method.
01:56So include ContactInfo.
01:57We have to write the module name.
02:00We will include that module and all of its functionality.
02:03It's exactly the same as if we typed all of those lines in right in place of
02:09where the word include is.
02:10So let's try that out.
02:11I am going to save that document.
02:12I am going to go into my command line.
02:14Notice that I am already inside my ruby_sandbox.
02:17I am going to open up irb with simple-prompt.
02:18I am going to load in that file, person.rb.
02:23So load just simply reads the contents of the file.
02:26That's exactly like if we had typed Ruby and the name of the file from the command line.
02:30Now, you may need to provide a full path to this file if you are not inside the
02:34directory where it already exists, but if it succeeds, it will come back and say true.
02:38So now that file is loaded.
02:39The difference between running from the command line is now we can interact with it.
02:42So let's say person = Person.new, person. first_name = "Joe", person.last_name = "Smith".
02:52Then we should say puts person.full_name. There we go.
02:59We do have our attributes there and we do have that full name method.
03:02All of that functionality from contact information was just dropped in to person.
03:06Of course the real benefit to that is that not only can it be in Person, but now
03:10we can also put it inside Teacher and inside Student, and now, if we decide to
03:14make a change to one of these methods and we say, oh, wait a minute, you know
03:17what, I actually want two spaces before the zip code.
03:20We make that change there and it happens everywhere that module is included.
03:24Now, module functionality is also inherited, so I just want to point out that we
03:28could also do something like this.
03:29Student, let's say, it will inherit from Person.
03:32Now I don't need to even declare this anymore, we can have different attributes here.
03:36Let's say that the Student has many books and grades, and our Teacher up here
03:43can have some different attributes, accessor, lesson_plans.
03:49So each of our classes is now different, but all three of them have
03:53contact information.
03:54These two have it because they explicitly included it, the Student inherited the
03:58behavior of Person and just added a few attributes to it, and inheriting from
04:01Person inherited that module's behaviors as well.
Collapse this transcript
Load, require, and include
00:00In the last movie, where we were looking at modules as mix-ins, we defined our
00:04module and the classes all in the same file, and we just made sure that the
00:08module came before the class, so that Ruby would have a definition for the
00:12module, so that it could include it when the class definition came up.
00:16Well, more typically, we would not put those in the same file.
00:19We would break them into separate files, and our modules would start to exist
00:23in their own files, like code libraries, that we could just mix-in that library
00:27whenever we needed.
00:28So frequently you will end up with these small little module files that you can
00:31draw upon whenever you need.
00:33Well, if we break it off into a separate file, what that means is that we have
00:36to have a way of making sure that Ruby has loaded in that module and knows
00:41that definition before we try and mix it in to one of our classes, like our
00:45Person class, and that gives us the perfect opportunity to take a look at
00:48three Ruby commands:
00:49Load, Require, and Include.
00:52Because the difference between these three methods frequently trips beginning
00:55programmers up, let's take a look at them.
00:57So in the last movie I created my Person class and then I also have a
01:00module, ContactInfo.
01:01What I want to do now is break that up into its own file.
01:04So I am going to start by just doing a Save As, and I will save this file
01:08as contact_info.rb.
01:11Now its in its own file, notice I am in contact_info.rb.
01:14I am going to erase everything that's not in that module.
01:17So now I have just a module definition in there.
01:19Let's move that out of the way.
01:21Let's go into the sandbox, and let's open up person.rb again, and now let's
01:25do the opposite here.
01:26Let's take away everything that's not our Person class definition.
01:30Now, I have still got Teacher and Student here. That's fine.
01:32I am just going to leave them for now.
01:33Typically you would probably break them off into their own files, but I am not
01:36going to worry about them while I go ahead and make the main point that I want
01:38to make, which is that, before we can include contact_info in this file, Ruby
01:44needs to know about contact_info. Let me show you.
01:47Let's go into the command line. Let's open up irb.
01:50Notice I am already in my ruby_sandbox, simple_prompt.
01:54Let's go ahead and just load in that person file, just like we did in the last movie.
01:59So person.rb, load that in. Wait a minute.
02:01It says uninitialized constant Person::ContactInfo.
02:05It's trying to find contact_info, and it can't.
02:08That's because we haven't loaded it in.
02:09Ruby doesn't know what it is, doesn't know how to find it, so it can't include it.
02:13So what we need to do is load, and then contact_info.rb, true.
02:20Now I am going to hit the up arrow twice and let's load in person.rb now.
02:24No problem this time.
02:25So as long as contact_info is loaded in first, we are okay to load in person.rb.
02:31So we could say that person.rb depends on contact_info, it's a dependency.
02:37So what we want to do is take this line, load, and put it at the top of the file.
02:42So that way the first thing that person. rb does is it loads in contact_info, and
02:48then it can go ahead and execute. Let's Save it.
02:50Let's try it.
02:51I will quit out of irb.
02:53Let's go back into irb, so we get a fresh copy.
02:56There is nothing stored in memory yet, and now let's just try load person.rb. True.
03:01It worked, because it first loaded in contact_info and then loaded in this file.
03:06So we have solved the problem.
03:08Now incidentally, this is a path here.
03:10It's not just a file name.
03:11It's the path to a file.
03:12We will be talking more about paths when we get to the section on files.
03:16But it works the same way that paths do.
03:18If you are used to working with Linux or DOS or anything like that.
03:22We can provide an absolute path, or we can provide a relative path to get to that file.
03:26So this solves the problem that we started with and it also illustrates how Load
03:30works and how Include works.
03:32So Include is used exclusively for bringing modules in as mix-ins.
03:37That's what its for.
03:38Include has nothing to do with loading in files.
03:41We use Load for that.
03:42Now, let me show you something about Load that's very important, which is that
03:45let's say load person.rb again, it loaded it again, loaded it again, and so on.
03:51Every time it returns true, because it loaded in those files again.
03:55If we have already loaded it in, if Ruby has already seen that definition,
03:58there's no reason to do it a second time.
04:00Each and every time that it loads in person.rb.
04:03It's also executing this load of contact_info again.
04:06But we don't need it to load those every single time.
04:10Let's say that we had Teacher and Student in their own class.
04:13We would want then to also have a statement at the top that would say
04:16load contact_info.rb, because each one of those would have the same kind of dependency.
04:22Well, we don't want to load contact_info three times.
04:24That's waste of time and energy, and it might actually have a negative impact
04:27on our program if somewhere along the way we have made changes to what's in contact_info.
04:32So a better way to do it, and which we will typically see instead is Require.
04:37Require works exactly the same as Load, the only difference is that Require
04:41keeps track of the fact that it's already included the file and only includes it
04:45if it hasn't been loaded before.
04:47Now, it's possible to trick Require by having some different paths to get to
04:51files, but for the most part it's pretty good.
04:53Now, let's also put it here.
04:54Let's say require.person.rb.
04:58Now, the first time I executed, it should return true to me, because it is
05:01requiring it for the first time.
05:03But now Require has added that file to its list of files that it knows it
05:07required, and now when I say require person.rb, it comes back and says false.
05:12It did not bring the file in again.
05:14It is still there, but require didn't do anything.
05:17So if you need to actually refresh the code and bring something in a second
05:21time, you will want to use Load, but more often than not what you want is just
05:25to bring this library in, so that Ruby knows about it, and then once you have
05:29required it, you don't need to read it in again.
05:30Ruby already knows about it.
05:32Now, you will want to pay careful attention if you have been programming
05:34in other languages, because these may have different meanings than they
05:37had in those languages.
05:38For example, if you are working in PHP, Include, it means load in a file, not
05:43include a module, so just be careful about that.
05:46So just to make sure that you are clear on the differences.
05:48Load loads in a source file every single time its called.
05:52It will always return true if the file is successfully loaded in.
05:56Require loads a source file only once, after that it keeps track of the
06:01fact that its loaded in, the fact that it knows about it, and it doesn't
06:03bother loading it again.
06:04It says, "oh yes, I have already seen that."
06:07Then last of all, Include is what we use for including modules.
06:11It has nothing to do with files and reading files in.
06:14It's only for bringing in that mix-in behavior of modules.
Collapse this transcript
Enumerable as a mixin
00:00Before we leave modules and move on, I want to give you a little bit of insight
00:04into way that Ruby uses modules inside its standard library of classes.
00:08Now, we've seen a number of methods so far, like sort, detect, select, reject,
00:13collect, and inject and even more that are shared between a number of different classes.
00:17We saw how we could use these on arrays and hashes and ranges and strings, and
00:22that they are used in more classes as well.
00:23And they might have slightly different behaviors on each one, but the same
00:27functionality essentially is part of all these classes.
00:30When you have shared functionality like that, it's a good indication that a
00:33module may be at work, and that's exactly what's happening with these classes.
00:36So here I am taking a look at the Ruby documentation at ruby-doc.org in the core
00:41library, and I've got a definition for array.
00:44Now we see all the methods that are in array, but notice here, it says
00:47Included Modules>Enumerable.
00:50Enumerable is an included module in array.
00:52Let's take a look at Hash, scroll down Included Modules>Enumerable and Range,
00:59Included Modules>Enumerable.
01:01String, same thing.
01:02It has Comparable and Enumerable in there.
01:05So the module that's being included in every case is Enumerable, and enumerable
01:09is just something that can be counted, right.
01:11If we have a set of things that can be counted, then we ought to be able to do
01:13something with them.
01:14We got to be able to sort them, we got to be able to collect them to search
01:18through them, and that functionality is mixed in to all of those sets, right.
01:23Arrange is a set, an array is a set, a hash is a set.
01:26So all of them have this enumerable behavior.
01:28Now if you look at the definition here for Enumerable, it tells you that it's a
01:31mixin and it provides collection classes, things which have a collection, with
01:36several traversal and searching methods and with the ability to sort.
01:39The one caveat is that class must provide a method each, which is going to
01:43yield successive members of the collection, and we saw how to do that when
01:47working with code blocks.
01:48We saw how to yield up a value.
01:50And then it goes on to say that if we want to use the max, min, or sort
01:53functionality, then we'll also need to provide the comparison operator so that
01:57it will know how to compare two different values.
01:59So we can see how Ruby goes about sharing this functionality between
02:04the different classes.
02:05And you could override any of those methods just like we saw you could do
02:08earlier if you want different functionality, but if not, we can include the
02:12module and get all of its functionality for free.
02:14All we have to do is provide this each method.
02:17Now here's where the advanced extra credit part comes in.
02:20We can mix in that Enumerable module for ourselves.
02:24Now while you can often get the same functionality just by putting an array
02:28inside your object, and using Enumerable off that array, it's really not that hard to do.
02:33So let's go ahead and just see how to do it even though most of the time, it's
02:36really an unnecessary step that you won't want to do.
02:39I have got a simple class here in to_ do_list.rb and I just have a simple
02:43attribute called items that I'm initializing as an empty array and then I have
02:47given some sample usage down here in the comments.
02:49We'd just initialize it, assign a list of to-do list items to the items array,
02:54and then we could call select on this array. It's an array.
02:58It already has enumerable mixed into it.
03:01So that's why I say this is not strictly necessary.
03:04Let's make the to-do list itself enumerable.
03:06All we have to do is say include Enumerable.
03:09We don't need to do any kind of require or anything, because it's already in Ruby.
03:13If Ruby is loaded then we have Enumerable.
03:15So include Enumerable.
03:17That will then give us all those features.
03:18But if you remember, the documentation told us that we need to have an
03:21each method declared.
03:23So it knows what is going to be rendered up, what are the enumerable things.
03:27We could have a lot of different things inside this to-do list, right.
03:30We could can have several attribute accessors.
03:31So we could have items, we could have completed items, so on.
03:36So it wants to know what exactly are you enumerating.
03:39We'll tell it, well, it's going to be items, items.each and then we'll just put
03:43in a code block, we know how to do this earlier and yield that value for items.
03:48So it will just yield up this value each and every time to Enumerable, so
03:52Enumerable can make use of it.
03:53That's all we have to do to get most of that Enumerable functionality.
03:57Let's save it and try it out.
03:59Let's go into command line.
04:01Notice I am already in my ruby_sandbox.
04:03I'll open up irb with simple prompt and now, let's do our require and the file
04:08is to_do_list.rb true.
04:12So it loaded it in.
04:14Now let's say list equals ToDoList. new and let's give our items a value.
04:21items equals and we'll just use the same ones, laundry and dishes and vacuum.
04:28Okay, so there is our array of items.
04:31Now we already know that we could do lists.items.select.
04:36That's the one we are using before select each item, if the item length is greater than 6.
04:42So it comes back with laundry.
04:44But what we've now done is we've put that enumerable on the object itself.
04:48So now list.select returns the same thing.
04:52We're essentially just sending the same array to it, but we don't have to be.
04:56We could be putting in something much more complex here.
04:59So what we were yielding up is some complicated calculated value maybe, maybe we
05:03are mashing together a couple of different objects.
05:06The important part is just that we've told Enumerable what collection should be enumerated.
05:10It can be a manufactured collection or a simple collection like an array, but we
05:14just have to tell it here is each item.
05:16That you will iterate through by using the each method, and from there, we get
05:20all of this other behavior built in.
05:22This is really isn't the most practical thing to use in the world.
05:25So don't go start using Enumerable all over the place.
05:28It really is for a sort of special complex case where you need to create an
05:32Enumerable class that doesn't already exist.
05:35Otherwise, most times, you would just use an array like we did here.
05:39We don't need to go that extra step.
05:40I did it just to make the point so that you could see how easy it is to mix in
05:45modules that give your classes lots of extra functionality.
Collapse this transcript
8. Working with Files
Input/output basics
00:00In this chapter, we are going to learn to work with files and directories in
00:03Ruby, and I think it will be helpful if we start up that discussion by first
00:06taking a look at the basics of input and output.
00:09Frequently, you'll see input and output abbreviated as simply I/O. So if you
00:13hear me say I/O, that's what I am referring to it as input and output.
00:16And what we were talking about is input into a Ruby program and output from that program.
00:21We've been using some of the basic Ruby output for some time now.
00:25We've been using both the puts and print, and we have seen how both of those
00:29work that's basic output, and so that our program can put something out to
00:34either the command line or to irb.
00:36Now input, we haven't really seen yet.
00:39We've been running a file, running our program, but that's not really input
00:42that's the program itself.
00:44Even in irb where we were typing things into the command line, that still is
00:47sort of writing the Ruby code itself.
00:50With input, what we really mean is getting information into the program.
00:54So instead of putting information out of the program, we'll use gets to
00:59get information back.
01:01Let's try it on the command line and see how it works.
01:02So I am in my command line, I am going to open up irb, I'll put simple prompt,
01:09and let's try out, gets.
01:11So if we just simply say gets, by itself, just gets.
01:16We don't get anything back. It just waits.
01:19It's waiting for us to give us some input.
01:21So let's type in Hello, and it returns the return value of gets is whatever I
01:29typed and then a liner turned at the end, because I did type a return at the end
01:32but it knew that was the ending of gets that's how it knew we were done getting
01:36input, and it also put that in that string there.
01:39So what we want to do is catch that value.
01:42So the easiest way to do that is just to assign into a variable.
01:45So let's say input equals gets.
01:48All right, it waits, Hello, and now, the value of input is equal to that user input.
01:55And then most of the time, we don't want this line ending there.
01:58It just gets in our way.
02:00So there is a really easy way to get rid of it.
02:02Ruby has something called the chomp method, and we can apply it to any string.
02:06So let's say that I have a string and say this is a test of chomp.
02:11I am going to put a line return at the end inside double quotes.
02:17So it is an actual line return there and then I am going to apply
02:20chomp, c-h-o-m-p to it.
02:23And it returns the string without the line ending.
02:26Now if the line ending had been an r instead or if it had been \r\in, those are
02:33the variations on line endings that different operating systems might use.
02:37They all still get chopped off at the end.
02:39That's what chomp does.
02:40chomp will remove the line ending if it's the last character.
02:44If it's somewhere in this string, it leaves it alone, only the last character.
02:49It also has another version which is chop.
02:52Let me just show you chop.
02:54It does the exact same thing, but the difference was chop.
02:57Let me show you this, is if I say Hello.chop, chop always removes the last
03:03character, whether it's a line return or not.
03:06So chomp is a little bit safer.
03:08So typically, we are going to want to use chomp and the way we would do it is
03:11just to say input equals gets, and just right away.
03:14As soon as that value comes back, chop off the end of it.
03:17So there it is, the input comes back.
03:19Let's say This is my input. This is my input.
03:23So I get a clean string that's ready to use.
03:27Now that demonstrates it in irb.
03:29Let's just quit out of irb and I'll clear that screen.
03:32Let's look at it inside a file.
03:35So I have got a file here in my ruby_sandbox called input_output.
03:38It will be in your exercise files or you can pause the movie and copy it down,
03:42but it's very simple.
03:43All I am doing is that same input equals gets chomp and I have got some
03:47reminders up here as to what those do.
03:49We've already seen print and puts but I have reminded you, what each of those does.
03:53Print doesn't put a line return, puts does put a line return at the end.
03:57So we are going to get some input and then we are going to output it back.
04:00And then the last example I have got it is just that we can use gets inside a
04:04loop, if we want to get multiple feedback.
04:07And so I have got a loop here that basically waits for me to say quit and when I
04:11say quit, then it access the loop, but until then, it just keeps getting user
04:15input, and then turning around and outputting that same value.
04:19Let's try running this program.
04:21So I'll just switch back to my command line.
04:23Notice that I am already in my ruby_ sandbox, ruby input_output.rb. So there it is.
04:30I ran the program and the first thing it does is it does the gets.
04:33So it's waiting for me to type something. Hello there.
04:37You just told me: Hello there..
04:39Notice I have extra period there that's not great programming, I added a period
04:42in my code and since I had a period here already, it doubled it.
04:46But now I have got this prompt, so that was something I did here with print.
04:50So we are getting that prompt now, and now it's waiting for me to type things.
04:53So I can say Hello, Again, And again and it just keeps repeating to me until
05:02finally, I type the magic word, quit.
05:05And then it gets that input, it outputs quit, because that's still part of that loop.
05:11After it gets the result and outputs it, but then when it goes through the loop
05:14the next time, result is equal to quit.
05:17So it access the loop and just puts the goodbye.
05:19So that's really all there is to user input, but it turns out to be a very
05:22powerful tool even though it's a very simple, because now we have the ability to
05:26run a program and our user can interact with it.
05:29It can be an interactive program.
05:30It can ask questions of the user, the user can input their choices, they can
05:34select from menu items, all sorts of things and we can run Ruby code based on that input.
05:39So now that we understand the basics of input and output, why is that important
05:44for learning to work with files and directories?
05:46Well, the reason why, because files are just a type of input and output.
05:50We are inputting things when we read from the file or outputting things when
05:54we write to a file.
05:56So it's just input and output still.
05:57In fact, there's a Ruby class that's called IO and it's an input/output class
06:03that handles the basics of input and output.
06:05And it handles various forms of input and output.
06:07We can send things across Internet connection and things like, but its main
06:11star, its primary subclass is file.
06:15And that's what we will be working with next is the file class, and we'll see
06:18how we can apply these I/O basics that we just learned.
06:21puts, print, gets, chomps, those will all be applicable to working with files.
Collapse this transcript
File system basics
00:00In this movie, we are going to take a look at some of the basic things you need
00:02to know about working with the file system.
00:04Now the real basics I am assuming that everyone knows.
00:07We have files on our hard drive, they're grouped into different folders, and we
00:11can navigate through those folders to find the files we want, and in the same
00:15way, we can do that from the command line, we can also do that inside our Ruby
00:20code in order for Ruby to be able to find those files.
00:23But there are couple of pitfalls that we need to watch out for, and that's what
00:26I want really cover in this movie.
00:28And they are especially tricky, because they're different on
00:31different platforms.
00:32Its cross-platform issues that we have, and the first pitfall is with the file
00:36path separators, and the second is with file permissions.
00:40With file path separators, it's a pitfall, because each of the platforms,
00:44Windows on one hand and Unix-based platforms like Linux and Mac OS X, on
00:49the other hand, use different separators between the folder names that lead to a file.
00:55So the separators of the path, the path to the file are different.
01:00On Unix, it's going to be a forward slash, on Windows it's a backward slash.
01:05And you may already know this from working on the command line.
01:07So which one of these do we use in our Ruby code, because we want our Ruby code
01:11to be cross-platform.
01:12We want it to be able to run in both places.
01:14The answer is that Ruby does a really good job of allowing you to always just
01:19use the forward slash.
01:21So you can use the forward slash, and even if you're on a Windows machine,
01:24everything should work fine.
01:26You don't want to ever use the backslash, because that probably will not work on
01:31a Unix-based machine.
01:33So forward slash is the better of the two, but there's an even better more
01:36professional way to handle it.
01:38And that's by using the file class.
01:40The file class has a class method called join and all that join does is take a
01:45series of strings and join them together with the appropriate separator.
01:49So on Unix, we get the forward slash and on Windows, we get the back slash.
01:54Now if you are on a Windows machine, and File.join gives you forward
01:57slashes, don't panic.
01:59File.join will take care of it.
02:00It will make sure that it gives you something that your machine can handle.
02:03So if you got forward slashes that means your machine was able to handle
02:07the forward slashes.
02:08Now the second issue is file permissions, and file permissions is just a general
02:12problem that sometimes jumps up and bites you that you need to know about.
02:17It's made even trickier by the fact that the way we handle it is different
02:20depending on whether we are on Unix or Windows.
02:22Every file on your computer has an owner of that file.
02:26Chances are that owner is you if it's a file you created.
02:29And it also has permissions that say who can read the file, who can write to the
02:33file, and if it's a program who can execute the file as well.
02:37The default behavior is going to be the most files on your local computer are
02:42owned by you and accessible by you.
02:44So it's not something you have to worry about a whole lot.
02:46Now I know there are exceptions, but most text files that you might have on your
02:50hard drive or something that you could work with.
02:52Now if you are on a network, then there's probably a lot of files that you
02:55are not allowed to touch, a lot of things that you are not allowed to have access to.
02:59So if we are going to run a program in a network environment, it would be
03:02something we would have to look into further.
03:04So I am going to give you some jumping off points, if you did want to look into it further.
03:08If you're using Unix, Linux, or Mac OS X, then you would want to look at chmod
03:14as the command to allow you to change the permissions for a file, and chown
03:19would allow you to change the owner.
03:21Those are just some very basics Unix commands, they also exist in Ruby, and
03:25there are some of Ruby methods that allow us to do chmod and chown as well.
03:30Now if you're on a Windows machine though, chmod and chown aren't going to
03:33be much use to you, because Windows has a different permissions model than Unix does.
03:38Instead, you are going to manage those files through the Properties/ Security tabs.
03:43So you click on Properties, then on the Security tab and you can change who the
03:47owner and the permissions are for the file.
03:49So I know that's not concrete solutions for how you would actually go about
03:53solving permissions problems, but the main thing is just to know that they
03:56exist, that there are permissions that would keep you from being able to write
03:59to a file, or keep you from being able to read from a file.
04:03But again, with most files that are easily accessible to you on your computer,
04:06you're going to have access to and you're going to have permissions for.
Collapse this transcript
File paths
00:00Now that we've seen how we can use Ruby to get the correct file path separators,
00:05we need to understand how we can get meaningful Files Paths.
00:07How we can locate the files that we either want to read from or write to.
00:11There are two ways that we can specify the path.
00:15The first is using an Absolute path.
00:17The Absolute path is the path from the root of the hard drive, from the very
00:21beginning, how do we locate that file?
00:23It's a path through the folders that would take, that we would have to open up
00:27till we got to that file.
00:29And we know that it's an Absolute path, because it begins with a forward slash
00:33and that lets us know starting at the beginning.
00:36The second type of path is a Relative path and that's a path from where we are
00:40right now, how do we get there?
00:42We don't care about going back to the beginning.
00:45We say from the current position what folders do we need to either open up or
00:50what parent directories do we need to jump backwards into?
00:53So you will see there in the Relative path example I have got, I have got ..
00:57that's when we want to move to a parent directory, move back one directory into
01:01the directory above us, and then a single . is the current directory.
01:05That's the directory we are in right now.
01:07So if we are going to use a Relative path, we need to know where we are, when we
01:11are running one of our Ruby programs.
01:14And Ruby gives us a variable that lets us know that, and it's _File_ and there's
01:18actually two underscores on either side of capitalized word File.
01:22And it's a special variable name that refers to the file that were in right now.
01:26So that's actually the File where these characters are typed.
01:30Now the File will just return the name of that file to us.
01:34If we want to actually find out where that file is, we will need to use a method
01:39on the file class, which is expand_ path and that says tell me what the full
01:43path, the Absolute path is to get to this file.
01:47Now while this works great for finding the file that we are in right now, if we
01:50want to find a different file, it's going to be much more useful if we start by
01:55using this Files directory and we do that with the dirname method.
01:59So dirname will tell us what directory is this file in and we can then use that
02:04as a starting point in our navigation, either to go deeper into other
02:08directories or back into a parent directory.
02:10Let's take a look at some code to see how it all works.
02:14Inside my ruby_sandbox and in the Exercise Files, I have a file
02:17called file_location.rb.
02:20You can pause the movie if you want to copy this down.
02:22At the top I have Absolute paths.
02:25To begin with, I have just got a simple string.
02:27That's all this is.
02:28It's a string using forward slashes.
02:30Even on Windows this will probably work as a file path.
02:34But the much better way to do it and what I am going to recommend to you is that
02:37you use File.join instead.
02:39That's really going to ensure that we have that platform independence.
02:42And what we are asking File.join to do is to build up that same string for us by
02:47appending those together.
02:48If we want it to be an Absolute path, the first item just needs to be an empty string.
02:53So with an empty string at the beginning, it will say okay, this is from the
02:55root Users, Kevin, Desktop, ruby_sandbox.
02:59Now you may have noticed the problem with Absolute paths which is that you
03:03probably don't have this same directory structure on your computer.
03:07For example, you probably don't have a folder called Kevin, unless your name
03:10happens to be Kevin too.
03:12So this doesn't make for great code.
03:13If I am going to write something you can't bring it on your computer and run it
03:17if it's going to ask for this Absolute path.
03:20Instead it's much better to use Relative paths.
03:24The first thing we'll see is what the value of that File variable actually is.
03:28That's this current file File_location.rb.
03:32That's what it's going to return to you is the name of that file.
03:34If we want to find out where that file is, we use expand_path.
03:38Now this is an Absolute path, but this is an Absolute path it's generated at the
03:43time it's being run, okay?
03:45We are asking Ruby to calculate that for us.
03:47So if you've got it on your hard drive, you will have whatever your hard drive
03:51structure is, whatever path it takes to get to it.
03:54It will not depend on you having something like what I have.
03:56So it's a much better way to do it.
03:58This is the way to do Absolute paths, to take a File or Relative path and then
04:02get the Absolute path from there.
04:04It's going to be much easier to navigate, if we start out by using dirname,
04:07so we will just take a look at what that value is, and then finally let's put it all together.
04:12We have got File.join, we have got the current file, we are taking it's
04:15directory and then I am backing up a directory into the parent directory, which
04:19in my case is going to be the Desktop.
04:21And then I am going into another folder which I have another folder here called
04:24Exercise Files, so that's what I am going into.
04:27I used it partly so that I could show you what happens when you have a space
04:31in the name of a file.
04:32I've escaped it with the slash and very important I've put it inside double quotes.
04:39So if you have a file with a space in the name, you want to take those two extra
04:42steps, escape the space with the backslash and put it in double quotes.
04:46Putting it in single quotes won't let this escape do its job, right?
04:50Remember that about double quotes.
04:51So when we put all of this together that will allow us to navigate in that
04:54Exercise Files folder and then from there we presumably would want to load up
04:59some file which I'm not doing it.
05:01Right now we are just going to output the string that's generated by this.
05:03So let's save that and let's just go to our command line and let's try running it.
05:08I am in my ruby_sandbox already, so I can just type ruby file_ location.rb.
05:13First thing we get back is just simply a string.
05:16Now we get the File.join that's building that string up for us.
05:20If you are on Windows, you may have gotten back slashes.
05:22If you got forward slashes, don't worry.
05:24It means Ruby thought that you could handle the forward slashes.
05:27And then we have got the name of the file.
05:29That's just the results of that file variable.
05:32Then we asked it to expand path on that, so that's the full path to get to the file.
05:37When we asked it to give that file's directory name, it said, well it's this
05:41directory, because it was able to say you are in the ruby_sandbox so it's this directory.
05:45That's just a single dot.
05:48If we want to get to Exercise Files from here, we would go . which is the
05:52current directory, back up a directory and then go into Exercise Files.
05:56Now let me just show you if we back up a directory into the Desktop, I can now
06:02run ruby ruby_ sandbox/file_location.rb that's the full path to get to the Ruby file.
06:08Now when I run it, it says the directory is ruby_sandbox.
06:12That's how we would get there from the Desktop, you would go into ruby_sandbox
06:16and then we would be in the right place.
06:18Now for getting the Exercise Files it says well you go into the ruby_sandbox,
06:23then you back up one, then you go into the Exercise Files.
06:25It's not very efficient sometimes, but it has been the net effect that we are looking for.
06:29And we could of course apply expand_ path on that and it would give us the
06:34Absolute path to those Exercise Files.
06:36It would stop being Relative.
06:38Now having these tools on how to work with File Paths, it's going to be
06:41essential for being able to find the files we want, so that we can be able to
06:45read and write from them, and that's what we are going to start doing next.
Collapse this transcript
Accessing files
00:00Now that we have talked about the basics of working with the file system, and
00:03we've seen how we can create paths to the files that we want to work with, it's
00:06time to see how we actually go about accessing those files.
00:10How do you open them up for reading and writing?
00:13There are two different ways that we can do it, and we'll take a look at both of them.
00:16The first is with File.new and the second one is File.open.
00:20Let's look at File.new in irb.
00:23So I will open up a new irb session with simple-prompt, and notice that I am
00:27inside my ruby_sandbox.
00:29That's important, because that's where things will be saved.
00:32That's where my files will go.
00:34The first approach, File.new, is instantiating a new file object, like you would think.
00:39So we want to assign that to a variable, just like we normally do when we
00:42instantiate an object.
00:44File.new wants two arguments.
00:46The first is the filename that we either want to read from or write to.
00:50We are going to create a new file and write to it.
00:52I am going to call it irb_testfile.txt.
00:58That will be the name of the file that it will create.
01:00The second argument is going to be the mode that we want to open it in.
01:04We are going to use write mode to start with, which is just to say w. We will
01:09talk more about modes in a minute, w is for write, r is for read. That's it.
01:14Now we've created this new file object.
01:16Now, take a look, all we did was instantiate it, but look here.
01:21It actually created the file for us.
01:23It's in my ruby_sandbox.
01:25So the file exists at the same time as this object exists, because that
01:30object is the file. That's what it is.
01:32It's in the file system.
01:34It's not like Microsoft Word, where you write a document and it doesn't actually
01:38exist in the file system until you hit Save.
01:41At this point we've instantiated a file, an actual file.
01:46Now, that file is open for us to write to, in the same way we might have a
01:51document open in a word processor.
01:52So we're now able to write to it, and when we are done, what we want to say is
01:56file.close, and you want to make sure that you always close your files.
02:00There are two main reasons.
02:01One is it makes sure that you don't accidentally write to the file when you don't mean to.
02:05And the second reason is because it allows Ruby to free up those resources that
02:09it was using to hold that file open.
02:11So you want to be a good citizen and always close up those files.
02:14Now, we didn't write anything to this file, we just opened it for writing and
02:18then closed it again.
02:19We will see how to write to it in a minute.
02:20Now let's look at the second way we could do it with open, but let's do that
02:23from an actual file instead of from irb.
02:26I am just going to type quit, and let's jump back over to the sandbox.
02:30I have a file here in the Exercise Files called accessing_files.rb.
02:35If you open that up, you will see its got the same thing we just did here for
02:38instantiating a file object.
02:40It has a different name, so this will create a new file.
02:42Then the second way we can access a file is using open.
02:47It works very much the same way, but instead of instantiating a file object, we
02:52just open a file and then pass it a block of instructions.
02:56That's just a code block.
02:58We do whatever instructions are in there, and at the end it closes it for us.
03:02So we never have to instantiate it.
03:03We don't have to hang on to this variable.
03:06We don't have to remember to close it. It does it for us.
03:08For that reason I find this works best most of the time.
03:12Use open instead of new, because it does close it for you, you don't have
03:16to remember to do it.
03:17And then it's also nice and clear, all the things you want to put in that file
03:21are just statements that are right here, or everything you want to do when you
03:24read back in from a file is a statement right here.
03:26Notice that we are using read this time.
03:29So we can go ahead and run it.
03:30Let's go ahead and just do that.
03:32I will open up the command line and we will just type ruby
03:36accessing_files.rb, and it runs it.
03:39Now, I don't get anything back, but it did what I asked it to.
03:44It did create file1.txt.
03:46It opened it for writing and then it closed it, then it opened it up for reading
03:50and then it closed it again.
03:51Before we move on to see how we can actually write information and read
03:55information from it, let's take a look at those file modes.
03:59There are six main file access modes that you are going to want to consider.
04:02There is r, which is read from the start, and for that the file must already exist.
04:07There is w, which writes from the start.
04:10If the file doesn't exist, it will create it.
04:13But if it does exist, it will wipe it clean.
04:16It will truncate it, so that there is nothing in it, and then start writing at the beginning.
04:20So you have to be careful, w is a little bit destructive if the file already exists.
04:24The third is append, and that lets us append to the end of a file.
04:28That's really useful if let's say we have a log file and we want to keep a
04:32log of the latest action that happened, maybe it was an order that came in or something.
04:36We can just simply open up a file, append the new information to the end, and
04:40then close the file again.
04:42Now, I noted that w is destructive, and that it really wipes the file clean.
04:46What if we want to read and write from a file but not erase everything that was there?
04:50Well, for that we need to use r+, which you will see over in the right column.
04:54That lets us both read and write.
04:56It does not destructively wipe out the document first.
05:00It just lets us both read and write and it puts us at the beginning of the
05:04document, ready to start.
05:05W+ lets us both read and write, but it does that same destructive truncating, so
05:11we don't use it that often.
05:13And then append+ does the same thing.
05:16It puts us at the end of the document and will let us both read and write, and
05:20we'll see how we can move around in the document a little later on.
05:22Now, most of the time what you are going to want are r, w, a, and r+.
05:29a is for the special case where you want to just append something at the end.
05:31W is most useful when you want to start a brand new document.
05:36And then r and r+ are the things you will use if you're just reading or you're going to read and write.
Collapse this transcript
Writing to files
00:00Now that we have seen how we can access files, and how we can open them up
00:04to enable us to write to them, let's see how we can actually write data to the file.
00:08Fortunately, because in the very first movie of this chapter we saw how to do
00:10the basics of input and output, it's going to be super simple.
00:13I want to start out by opening up the irb_ testfile.txt that we created in the last movie.
00:19It should just be a blank file.
00:21But let's type something in there, This is a test.
00:24You can type anything you want.
00:26Save it, close it up, now it has some text in there.
00:29Now I am going to go into irb.
00:31Notice I am already in my ruby_ sandbox where that file is located,
00:34simple-prompt, and I am going to just instantiate a new file, File.new, and it
00:43will be that file name, irb_testfile.txt.
00:47You want to make sure you type the name correctly otherwise it will create a new file.
00:52What we want to do instead is open that file and actually overwrite what's there.
00:56That's what I want you to see.
00:57So I've instantiated it now.
00:59Let's go take a look.
01:01Open up irb_testfile.txt and you'll find that its empty.
01:06So at the moment that we instantiate it, it wipes it clean.
01:10Now let's see how we can actually write data to this file.
01:13Before when we wanted to output data, we used puts.
01:16Well, we can use the same thing here, we just do it as a instance method,
01:20file.puts, and then whatever we want it to put, let's say abcd.
01:26Now let's take a look.
01:27It returned nil to us, just like normal.
01:29Let's go back over and look at the file again. It's not there.
01:32So whenever we write something to a file, it waits for us to actually close the
01:36file before it writes all of that data.
01:39That makes sense, I mean every time that it's going to write a little tiny bit
01:43of data, it would have to access the hard drive again.
01:47So if we were going to output let's say a thousand rows that we were composing,
01:51then it would have to access the hard drive a thousand times.
01:54It's much better to assemble all of that and then write to the hard drive just one time.
01:59So let's go ahead and say file.close, just so we can see that. Let's close it.
02:04Open up irb_testfile.txt, and there we go, you see it's there.
02:06So now let's just go back and open the file again.
02:10We are going to overwrite what was there, so we are going to need to
02:13do file.puts "abcd".
02:16Now, as you might guess, we also have file.print available to us.
02:20So we have efgh that we can print, and the difference is that print doesn't put
02:25a line return like puts does.
02:27There are also two others that are basically the same as print, with just subtle
02:30differences, file.write "ijkl", and that will do the same thing as print.
02:37It will write to the file, but notice that it returned something besides nil.
02:42Instead, it actually returns the number of characters that it wrote.
02:47So if you feel more comfortable using write instead of print, that's fine.
02:51Either one works the exact same way.
02:53Then last of all, we can append to the file, to the file object, we can use the
02:57append method and append mnop to it.
03:00The only difference is that it will return the file object to us.
03:04Otherwise it's essentially the same as print and write.
03:07So last of all, let's just close this up.
03:09We can go take a look to see what's there, irb_testfile.txt, and it's exactly
03:15what you would expect.
03:17We had also created this file1.txt.
03:20I am just going to open up accessing_ files.rb, because I've written something in
03:23here that we can use to populate that.
03:25So again, we are just going to open up that file for writing, and then I am
03:29going to put in Ruby programming with a line return.
03:33I don't have to use puts to get a line return, I can always just put my own as
03:36long as I put it in double quotes.
03:39So use this line return in double quotes, and then it will return the line that
03:44I am doing the write and the fun and close it, exact same thing.
03:46Let's just open this up, we will quit out of irb, and instead we will run the
03:52file, accessing_ files.rb.
03:55It doesn't return anything to us.
03:57But if we go and we take a look over here, we will see that file1.txt does have
04:03those three lines in it.
04:04That's all there is to being able to write to files.
Collapse this transcript
Reading from files
00:00Now that we know how to write data to files, it's time to see how to read data
00:04back from files, and fortunately it's just as easy.
00:08In the last movie, I wrote the irbtestfile.txt and I just put the alphabet from
00:13a to p with a line break after the d. So that's what we are looking at.
00:16That's the text we're going to be working with. I'll close that up.
00:19Let's go back into irb, notice I'm in my ruby_sandbox, simple-prompt.
00:26So let's go ahead and just instantiate a new file.
00:28I am going to use the instantiation method because I want to step through the process.
00:32I don't want to execute the whole block of code at one time.
00:35irbttestfile.txt and then read.
00:42We are going to read back from this time, not write.
00:45Write would overwrite what we have there; instead we want to read.
00:48So now, if we used puts to put information into the file, then guess what?
00:53We use gets to get a line back out of the file and notice it includes the line return.
00:59It is in fact the mirror image of puts.
01:01Puts a line plus a line return; gets gets a line plus the line return.
01:07And we've seen how we could use file. gets.chomp, and that will return the next
01:12line without the line return.
01:13Let's try running file.gets. chomp one last time now. Oh!
01:19We get back an error, because this time there was nothing left to get.
01:23So we need to be careful when we use chomp, we need to make sure we can
01:27get something first.
01:28When we get to the end of the file, there is nothing there. returns nil.
01:31Watch file.gets returns nil.
01:34Nil can't handle chomp.
01:36It won't chomp anything off the end of nil.
01:39So unlike where we are getting user input where we can just use chomp
01:43automatically on top of the gets, we're going to have to be a little more
01:46careful here when we are reading from a file and first make sure that we did
01:49get something back.
01:50So I am going to go ahead and just do file. close and then let's reopen that file again.
01:55This time though, instead of reading a full-line, I am going to show you how we
01:59can do to read to read back part of a line.
02:03So we used write earlier and that wrote something without a line return, it just
02:07wrote a few characters and returned the number of characters.
02:11Well now with read we just tell it, well how many characters do we want to read? Read 4 characters.
02:16So there is 4. Let's tell it to read 3.
02:20It gave me the line return and nef.
02:24Line returns still counts as a character.
02:26Let's asked it to read us another 3, ghi and so on.
02:31So those are the two primary ways that we can read from the file.
02:33We can either get back a whole line or we can get back just a certain number of characters.
02:39Now that reads data but we have a lot of data, if we've a lot of lines, we don't
02:43want to do this one at a time, right?
02:45We want to actually loop through it.
02:47Let me show you how we can make that kind of loop.
02:48Let's do a file.close, be good citizens and close up our file and then I'll
02:53go ahead and hit Quit.
02:55Let's switch over to accessing_files.rb. This is the file we're working with.
03:00We had it output 'Ruby programming is fun' to file1.txt, we wrote that.
03:05This will overwrite that with the same thing again when I run it, but now I am
03:10actually read back in using a loop.
03:12Now notice what we've done here. while line = file.gets, so while there is a
03:18new line, if it returns nil, the loop exits.
03:21So that's a good way to loop through and get each line one after another.
03:26Then I have applied chomp down here, not up here. Remember that gives me a problem.
03:31So instead we want to make sure it exists.
03:32And then if it exists, chomp off the end of it, reverse it and put it
03:37inside these asterisks.
03:40Now if you know that you're going to loop through each and every line and that's
03:44really what you're after, then an easier way to do is with each line.
03:48So we just open up the file and then we say, all right, file, go through
03:51each one of your lines and taking that line in my code block, what do I want to do with it?
03:57And here I am just going to upcase it.
03:59So let's save it, let's see how this works.
04:01We're going to the Terminal, I am in my ruby_sandbox, so I just have to do ruby
04:05accessing_files.rb and there we go.
04:08The first one uses a gets loop to go through each one.
04:12The second one just uses each line to go through and process it.
04:15Essentially, they both do the same thing.
04:17Each line just might be a little easier for you to write.
Collapse this transcript
File pointer
00:00In this movie, I want to explain what the file pointer is and show you how
00:03you can manipulate it.
00:04The file pointer works a lot like the cursor does inside your word
00:07processing program.
00:09You can use the arrows to move around the text until you find the position that
00:12you want and then you can start typing and it'll start typing at that spot.
00:16Well the file pointer works the same way with a couple of differences.
00:19First of all, if the file pointer is at a certain spot, it doesn't insert text.
00:24It overwrites text.
00:25So be careful about that.
00:27The second difference is that we use the file pointer not just for writing to
00:30files but also for reading from files.
00:33And you may have noticed that in the last movie, when we're reading back data
00:36from a file, if we asked it to give us 5 characters, then when we asked it for
00:40another five, it started after those first five. It kept track.
00:44It moved the pointer along to keep track of the fact that it had already given
00:48us 5 characters and it didn't give them to us again.
00:50And if we did a gets then it advanced the file pointer go to the beginning of
00:54the next line, so that the next gets would return the next line.
00:57Let's see how we can find out the location of the file pointer and also move it
01:01to different locations.
01:03I am going to be using irb_ testfile.txt that we created earlier.
01:06It's a real simple text file, you can use any bit of text that you want.
01:09Mine is just letters a through p with a line return after the d. I am going to open
01:14up my command line, I will do irb simple- prompt and notice I am already in my ruby_sandbox.
01:21From there I'll instantiate a new file, File.new irb_testfile.txt, and
01:29we'll open it in r+ mode.
01:31Remember we are going to read from it and also write from it and r+ puts us at
01:35the beginning of the file.
01:37So we can find out that we are at the beginning of the file by finding its position.
01:40file.pos and that's how we find out the current position.
01:44Just like an array it starts counting with zero.
01:45And if we now say file.read(3), that will return three characters or three bytes to us, abc.
01:54Now if we go up, file.pos, we are at 3 now.
01:57It's moved the pointer along to 3 and if we do another read,
02:00the same thing would happen.
02:02Let's do a file.gets now.
02:05Notice that while we've been casually saying that gets returns a line to us,
02:10it doesn't actually.
02:12What it does is it returns everything from the current file pointer position all
02:16the way till it gets to the end of the line.
02:18So if we change the position to move over one at the beginning and then do the gets,
02:22every single line would be missing its first character.
02:26Now if we ask for a file.pos, you'll notice that position is not 0 because
02:31we hit the new line.
02:32It just keeps on counting.
02:33It goes to the entire document as one long series of numbers.
02:37It doesn't wrap around it at all.
02:39Inside the file, it doesn't care about the difference between the d and the line return.
02:43Those are both considered one character.
02:46And we can move around inside the file too.
02:47For example, let's say file.pos= and we can give it a position, let's say 13,
02:55file. and let's read back 3 again, m, n, and o. So at position 13, that's the text that's there.
03:02Now the position moved when I did that.
03:05Now I am at 16 because it advanced it when I did the read operation, so just
03:09be careful about that.
03:11So there should be one more letter there, file.read(10).
03:16Let's see that file.pos is now equal to 17.
03:20So when I did to read, it stopped at the end.
03:22Just stopped right there at the end.
03:24It said okay now you are at the end and we can actually say file.eof? true.
03:30It is at the end of the file and if we weren't at the end of the file, it would
03:33return false of course.
03:35Now we can write something if we want here.
03:37Let's do file.write and let's do qrst and we can also jump back to the beginning
03:45of the file, we could use file.pos=0.
03:48We know how to do that but we also can use file.rewind and that takes us back to
03:53the beginning as well.
03:54I want to show you that you can use file.pos+= if you want to go from the
03:59current position, if you want to move forward 6 from wherever we are.
04:04Now we could a file.read(1). That's what I get.
04:08I can do the same thing file.pos-=.
04:11Let's just go back 2, file.read(2). I should get back e and f.
04:17So that's really all you need to know about being able to move the file pointer
04:21around inside the file so that you can read and write at various spots.
04:25Now there's too big pitfalls that I need to caution you about though because
04:29they can trip you up.
04:30The first is let's do a file.rewind.
04:33Okay now I am back at the beginning of my file.
04:35There is something called file.lineno and that, you may think, oh, that's the line number.
04:42Let's do file.gets and then let's ask for the next line number. Okay, now it's 1.
04:47It seems to be it's returning the line number but it's not.
04:52Don't get tripped up by this.
04:53It is an internal counter that gets uses, gets and also another method called
04:59read line and they used it to keep track of what line they're on at the time. Let me show you.
05:04We have done a gets now.
05:05Let's change our position now, file.pos=0.
05:08We'll go back to the beginning. file.lineno, still on 1.
05:14It has not changed.
05:16And if I say file.gets, now file line number is equal to 2.
05:21Line number is just an internal counter that keeps track of how many times
05:24gets has been called.
05:26It has no relationship whatsoever to the file pointer. It has nothing to do with
05:31the file pointer, so do not get fooled into thinking that.
05:35If we were to do file.rewind, there's one slight difference between setting the
05:39position equal to rewind, which is position equal,
05:42it does nothing to line number. rewind also sets line number back to 0 at the same time.
05:47So file.lineno is back at 0.
05:49So what is this line number thing good for then, if doesn't actually tell us the lines?
05:53Well it's useful if you're just going through and using gets over and over and
05:57over again to know what line you're on. Let me show you.
06:00Let's write a real simple while line = file.gets and let me just paste in a line
06:08of code here so I don't have to retype it, puts and then we'll output the line
06:13number and then the line and then end. So there we go.
06:17Now we have been able to sort of prefix every one of our lines with the line number.
06:21That's the kind of thing that it's good for.
06:23Now the second pitfall that you need to watch out for is that you can set the
06:26position beyond the end of the file.
06:29When we were doing a read, remember it stopped at the p. It didn't keep going
06:33but we can set the position.
06:34Let's say file.pos+=, and let's say 100.
06:40So now I'm position 121 of my document and you know that I only have the letters
06:46a through t now, right?
06:47You can see that in the gets that we just did.
06:50So I definitely don't have 121.
06:53If I do a file.read(1), it returns nil.
06:57That's what it reads there.
06:58There's nothing, but I can do a file.write. Let's do xyz.
07:03So it did successfully write it.
07:05Let's go ahead and do this loop that we just did up here, the gets loop.
07:08Let's do that again and see what we get back this time.
07:11So let's do file.rewind, get back to the beginning and then while line =
07:16file.gets and I'll paste in that same line again.
07:21Now it looks like it worked there.
07:22It looks like it did what we would want.
07:24It just started writing at the end of the file.
07:27Let's say file.close now and let's just reopen our file one more time, file =
07:35File.new "irb_testfile.txt" and we'll open it in both reading-writing mode again.
07:44file.gets, file.gets. Now look at that.
07:52So when we did it this way, it seemed to all work just fine.
07:58But when I did it this way, look what we got back.
08:01When it wrote, it wrote a bunch of invisible characters, almost 100 of them
08:06because that's how far we jumped ahead.
08:08This is the octal notation for nil.
08:11So what it's doing is it's taking all of those nils and converting them into
08:14invisible characters.
08:16In fact, let's just look here.
08:17If we open up irb_testfile, they look empty, right?
08:21It looks like there's nothing there but in fact they are.
08:24It's being written with these real strange characters, which can throw
08:27things off for you.
08:28So I want you to be really careful about writing beyond the end of your document.
08:33You can always rewind to the beginning of it and then do gets until you get to
08:37the bottom and when gets returns nil, you'll know you're at the bottom, then you
08:40can start writing but don't just sort of use position to jump off into outer space
08:45and start writing or you'll get this kind of unpredictable behavior.
08:48If you keep those two pitfalls in mind though, moving around inside the
08:51document will be really easy.
Collapse this transcript
Renaming and deleting files
00:00Now that we know how to read and write from files, let's see how we can rename
00:04our files and delete them.
00:06So I am going to do the renaming and deleting from irb rather than inside a script.
00:10Let's do simple-prompt, open up irb, and I'll create a new file to start
00:16out with that we can rename and then delete when we are done.
00:19So file equals File.new and let's call this file_to_rename.txt and we'll go
00:27ahead and just say we are going to write.
00:29And while we are at it, we'll say puts "This is a file for renaming and then deleting".
00:40file.close.
00:41All right, so now we've got our file there.
00:43Let's just double-check.
00:44Look at our sandbox, file_to_rename, there it is in my ruby_sandbox.
00:48You want to make sure that where you are located is where it'll be.
00:52So now let's see how to rename it.
00:53It's nice and simple. We just use the File class and call the rename class method.
00:58So File.rename, and we give it the old name as the first argument,
01:01'file_to_rename.txt', and then the second argument will be the new name of the file.
01:09Since we are going to delete it next, let's call it 'file_to_delete.txt' and that's it.
01:15That's all there is to being able to rename a file.
01:17If we look here now, it's called file_to_delete. It works really well.
01:22Deleting works just as easily File.delete and then now it's
01:27called file_to_delete.txt. Here it is.
01:31Let me take a look.
01:33Sure enough now the file is gone.
01:35So that's really all there is to the syntax of being able to rename and delete files.
01:39One thing you need to really watch out for though is that with read and write,
01:42we had to make sure that we had read and write access to the file, but if we are
01:46going to rename and delete, in addition to having write access to the file,
01:50we also need write permissions on the directory that contains the files.
01:54So you want to watch out for that.
01:56The other question that I want to address that sometimes comes up is what about copy,
01:59what if we want to copy a file?
02:00Let's create a new file again.
02:03Let's go back up here and make a new one, but this time we are going to call it
02:06file_to_copy and then we'll just go ahead and close it.
02:10We don't need to put anything inside.
02:11That will create the file for us.
02:13Take a look and confirm that it's there, file_to_copy.
02:15So now, let's take that file and let's say File.copy and let's try using the
02:21same syntax as rename.
02:22Let's do file_to_copy.txt and let's give it a new name for the new copy.
02:29We'll just call it copied.txt. Let's close it up.
02:34Oops! there is no copy method on the File class. Instead the way that we copy files is
02:41by including one of the standard libraries that comes with Ruby.
02:45It ships with Ruby.
02:46It's already there but it's not loaded up, but we know how to load things up.
02:49We just use, require, require and it's going to be called fileutiles.
02:57That's all we've to type is require 'fileutiles'.
02:59It comes up true, means that it loaded in all that Ruby code.
03:02It's just sitting there waiting to be loaded and now we can say FileUtils.cp
03:11for copy or copy and then let's do file to copy.txt, and this time, let's call
03:20it copied_file.txt.
03:25Take a look, and sure enough, here's my copied_file and my file_to_copy.
03:29So that fileutils is the way to get the copy functionality.
03:33So in fact, let me break it down for you a little more.
03:36The file class gives us rename and delete among all the other options of
03:40course that we've seen, all the other methods we've been looking at throughout this chapter.
03:43But we have rename and delete there, and unlink is a synonym for delete.
03:46So you can use that if you would rather.
03:47Then we have this file utilities class that we can load in.
03:50It's part of the Ruby standard library.
03:52require 'fileutils' brings it in so that we can use it.
03:55And we have copy, move, and remove all in there and you'll notice that the two
04:00letter abbreviations cp, mv and rm. If you're familiar with working with Linux in
04:04the command line, you'll recognize those as being the kinds of command lines you
04:08would enter in Unix.
04:10So that's really what File Utility is doing.
04:12It's giving us a Ruby interface to all those things that we normally would do
04:15from the command line.
04:16So we also have cd, chmod, chown, pwd, ln, touch, make directory, remove
04:22directory, all of those are available to us in file utilities as well.
04:25So it's very useful.
04:26I wanted to caution you against using something else that's called FTools.
04:30That's also a part of the Ruby 1.8 standard library. You probably have it.
04:35You can use require ftools, and what it does is it's a module that adds a lot of
04:39these fileutils features to file, especially copy.
04:43So we have copy then inside our file class and that File.copy would work, but
04:48it's not recommended that you use FTools.
04:50It's better to use FileUtils for a lot of reasons.
04:53The biggest reason though is that it's going to be removed from the standard
04:56library in Ruby 1.9.
04:59So pretend that it doesn't exist, just ignore it. As soon as you see it, think
05:02oh, that's not something I want to use. File and FileUtils are going to handle
05:06all of your file renaming, deleting, and copying needs.
Collapse this transcript
Examining file details
00:00In addition to reading, writing and deleting files, a lot of times we want to
00:04actually just find out some basic information about the file and that's what
00:07we're going to see how to do in this movie.
00:08To demonstrate, I am going to go into irb. Notice I am already in my
00:11ruby_sandbox, simple-prompt.
00:15Before we start, I am going to just assign a variable file equal to a string and
00:20that will be the name of the file, and let's make this that irb_testfile.txt or
00:25you can put any filename you want.
00:27Any file that you know already exists.
00:29We're just going to be checking out information about that file.
00:31So that's my file, I can then use the string instead of having to type that
00:35all out from now on.
00:36I can just pass the variable file in.
00:37There is a number of class methods on the file class that let us check
00:41out information, File.exist, for example, very handy for finding out if a file exists.
00:47If we want to find out whether it exist before we try to read to it, write it,
00:51rename it, delete it, that's very useful and we'll use that a lot.
00:54We also can check to see whether it's actually a file. file, true.
00:59Well, we say, well what's the alternative?
01:01Well, it could be a directory.
01:02A directory will also return true that it exists, but then we can tell the
01:06differences whether it's a file or not by using file or directory.
01:10We can also check whether it's readable, true.
01:15Is our file writable? File.
01:19How about executable?
01:21Now, this would be for scripts and for applications that have the executable
01:26permission set, my file doesn't by default.
01:28You can also checkout file size, File. size(file) and that's going to return
01:34in bytes the answer.
01:36124, that's the how large my file is.
01:39Now that's the number of characters that are in there, if you are using a
01:42single-byte language.
01:43So that's also really useful, and it's especially useful for making sure that
01:47you don't write beyond the end of the file.
01:49Remember, we talked about that how we could set the position beyond the end of
01:52the file, and there were some pitfalls that came with that.
01:54Well, size helps us make sure we don't go too far in the file.
01:58We've also seen a couple already that we'll just review, we had File.dirname
02:01that will show the directory of the file.
02:04So the directory is the directory I am in now, which is ruby_sandbox while I am running irb.
02:10We also saw File.expand_path.
02:15So that expands to show us the full path of where the file is located.
02:18We have something that's sort of the opposite of that File.basename which I've
02:23just putted on the string.
02:25It just returns the string to me.
02:26That's no magic there, right?
02:28But if I do expand the path, let's do a File.expand_path, and let's set
02:34that equal to full_path.
02:36So we'll just set that equal to variable.
02:38Now if we do File.basename on full_path, we'll get back just the name of the file.
02:46So it really is sort of the reverse of expand_path.
02:48If you want to expand it to get the full thing, basename says just give
02:51me what's at the end.
02:52It's also File.extname, the extension name, and we can call that, and it gives
02:58us back.txt in this case.
03:00That's useful, especially if you are working with images when you know if it's a
03:03JPEG or something, you can use that.
03:05The three more that I want to show you, and then I want to explain a little further.
03:08We have File.atime(file), File. mtime(file) and File.ctime(file).
03:19So it just all three of those give you back a time related to the file.
03:22Let's talk about what each one is, because it can be confusing.
03:25File.mtime is the last modified time and that's pretty simple
03:29and straightforward.
03:30It's the time the file was last written to.
03:32File.atime is the last time it was accessed, even when it's been read.
03:37It lets us know whenever it's been read from or written to.
03:40We don't know which one happened, unless we also look at mtime and then we
03:43might be able to tell.
03:44But mtime is write, atime is read or write.
03:48ctime is the last status change time.
03:52It's not the created time.
03:53It confuses a lot of people.
03:55It is not created time and people think well, I've modified, I've accessed,
03:59what about created?
04:00That's because it's not possible to find out the created time of a file.
04:04I mean, after all what is the created time?
04:06If I retrieve a file from a backup copy and put it on my hard drive, was it
04:10created at the time that it was backed up or created on my hard drive, right?
04:13It was the time that it was modified.
04:16So ctime, let's talk about what it is, is the last time that the status changed.
04:20That means that it was read to or written from, or any changes to owner,
04:25group and permissions.
04:26In general, try not to use it. Unless what you are really trying to find out is
04:30when the owner, group or permission is changed, there is no reason to use it.
04:34So just avoid it and stay away from it, but it's definitely not created time.
04:38That covers most of these class methods on the file class.
04:40But what about when we're working on a file, right?
04:43What if we have myfile = File.new(file), and let's open it up for reading.
04:50All right, so I am going to open that file up.
04:52I am now inside the file.
04:54Inside, I have an instance. The instance is called myfile.
04:57Notice that I called it myfile so it wouldn't conflict with file that we
05:00had already created.
05:01You want to be careful about using this word file too often or you'll get confused.
05:04So I've called it myfile.
05:06It's now an instance. Can we called instance methods on it?
05:09Let's try myfile.size, no.
05:11myfile.readable, no.
05:16Those methods don't exist as instance methods on the file class.
05:20However, we have something called stat, myfile.stat, and that returns
05:27a File::Stat object.
05:30Class is File::Stat and you can look inside there and you can see a lot of the
05:34attributes that it has.
05:36So a lot of these things are there, like size.
05:38So we can say myfile.stat.size and find out the size, or myfile.stat.readable.
05:47And we can find out whether it's readable or not.
05:49So that's the way you do it.
05:50From inside, you just have to make this one extra step to call for that stat
05:54object, and once that stat object appears, and you have it ready for you to
05:58work with, then you can call all those methods as instance methods on that stat object.
06:03Again, I find that that's especially useful, if we need to stop and check
06:06the size of the document to make sure that we aren't writing past the end of the file.
06:10And that's really all there is to it.
06:11Let's go ahead and close up our file, just for good measure.
06:13Now that we know how to find out information about our files.
06:17It really concludes a full understanding of how we can work with files,
06:21but we still haven't talked about directories, the folders that house our files.
06:25Let's look at that next.
Collapse this transcript
Working with directories
00:00Now that we understand how to work with files in Ruby, it's important that we
00:03also understand how to work with directories.
00:05Because we're going to want to navigate around directories to find our files,
00:08and we'll want to create and delete directories in order to organize our files.
00:11Fortunately for us, working with directories is very similar to working with files.
00:16Before we go into IRB, I want to take a look at my ruby_sandbox.
00:19That's the directory I'll be using.
00:20You could use any directory you want, doesn't matter, but take note of
00:23the contents of it.
00:25I've got accessing_files, all the way down to, to_do_list.
00:29Those are the files that are in that directory that I can see.
00:31Now, let's switch over to the command line.
00:34Notice that I am already inside my ruby_sandbox. If you are on a Windows
00:38machine, once you are in the directory you want, you'll type dir to get a list
00:41of the contents of the directory.
00:43If you are on a Linux, Unix or Mac machine, you'll type ls dash la.
00:49Now, we can view the full listing of these files.
00:51I wanted to use those extra options because I wanted to show you that there are
00:55some files that appear above accessing_files.
00:58Now if you don't have the same thing as me, don't worry.
01:00I just want you to be aware that it's possible that you would.
01:04.DS_Store is an invisible file.
01:07That's what the dot tells us. It's invisible.
01:09It means that it's basically a configuration file.
01:11It's not a real file that we normally want to worry about, in the sense that we
01:14usually work with files.
01:16So the operating system hides it from us.
01:18Now DS_Store happens to be a configuration file that the Mac operating system
01:22uses to keep track of things like the size of the window and the position on
01:26the screen, and that's how it keeps track of it.
01:28It's in this little file.
01:29Now there is a couple of others up here though, we've got dot dot, which is the
01:33parent of this directory, and dot, which is this directory.
01:36It seems kind of strange to have this directory as an item inside this directory.
01:42But what we're actually looking at is the directory listing, right. It's sort of
01:45index of items that the directory knows about.
01:48So it knows about all the items that are inside of it, but it also knows where
01:51its parent directory is.
01:52It knows what parent it belongs to, and so it has an entry for that.
01:56It also has an entry for itself. Why?
01:59Because that way it can keep track of the permissions that are on it.
02:02So it can use that entry about itself to keep track of information about itself.
02:07So these items that begin with the dot at the beginning, we'll just want to be
02:10aware of as we are working.
02:11We'll either want to filter them out or skip over them or something, and get to the real files.
02:16But those are considered entries in the directory.
02:19So let me just clear my screen here.
02:21I am going to open up an irb session and notice that I am already inside my ruby_sandbox.
02:26That's important.
02:28We've seen already how we can use File.dirname and that special variable file to
02:32find out the directory of the file that we're in.
02:34Well, we are not in a file, we are inside irb, but irb still returns the
02:38directory that we're in, which is ruby_sandbox, and we can check that
02:42with expand_path.
02:43We saw that earlier, sure enough that's where we are.
02:46We are in the ruby_sandbox.
02:48Now, this is what you want to use inside your Ruby files, inside your code, your RB files.
02:53You want to use File.dirname file, because that gives you your starting point
02:56relative to that file.
02:58We also have the directory class, Dir, and it has some methods, one of which is pwd.
03:03That stands for path to working directory.
03:07That tells us where we are right now.
03:10Now it return to the same thing that this whole expand path did, when I gave it the dirname.
03:15You still in your code want to use, File. dirname(__File__), because PWD can change.
03:20It keeps track of where we are right at this moment.
03:23This is saying relative to this file.
03:25That will always be the same.
03:27It will never change.
03:28PWD can change as we move around, and we have the ability to move around.
03:32We can tell the directory class, you know what? Move around. Let's go to chdir
03:37for change directory and let's go back one.
03:40Let's go into my parent directory, with dot dot.
03:43Let's now try Dir.pwd. Sure enough, I am now on my desktop.
03:48Dir.chdir will also take a absolute path as well as a relative path.
03:54I am just going to paste something in here, so you don't have to watch me type it.
03:57But we saw how to do that effectively with file join earlier.
03:59So we make sure we get the right line separators, the empty string at the
04:03beginning says start at root and then we string all of these together to come up
04:07with a string, with the right separators, and we can change directory into there,
04:11and they are sure enough we are back in our ruby_sandbox.
04:14So that let's us move around.
04:16What about the contents of the directory though.
04:18How do we actually work with those contents?
04:20Well, we call the entries class method on the directory class.
04:25So entries and then tell it what directory, right. It doesn't know what directories.
04:29It's not an instance.
04:29So I am going to say this directory.
04:32So there is the list of entries.
04:34It's just an array.
04:35It's an array of strings.
04:36Now we can turn on and pass those strings to the file class, we could open each
04:40one up, do something, or we could filter through.
04:42We can look for only files that begin with the letter A for example, and then we
04:46could do something to those, delete them perhaps.
04:48The important thing is that all it is, is an array. It can be sorted.
04:51It can be collected.
04:52It just simply an array.
04:54Most often what we want to do with that though is we want to call each on it,
04:59and that will let us go through each entry.
05:01We'll just make it code block.
05:03Let's start out by saying print entry plus colon space, so that will print
05:10the name of this file.
05:11That string will get printed with the colon after it.
05:14Then let's use some of those methods we worked on earlier. Let's say If File.
05:19is a file, entry and File.readable, check and see if it's readable or not,
05:28entry, then that's File.open up the file and we're going to open the file name,
05:36we'll read from it.
05:38We'll be in read mode, we'll pass another code block, which will return the file
05:42that we can work with, and then puts file.gets, so that will just get back
05:47the first line of the file, and it will output it to irb.
05:51That's what it's going to do, and in that code block,
05:53let's go ahead and put an else statement in here, just because if it's not a
05:59readable file, I did a print up here, and I just want to do a line ending.
06:04So I'll just do a simple puts.
06:06So we'll just put a line ending and then return from there.
06:09So puts and then end, and then finally last of all, let's do a final end, here we go.
06:15So there it went, an output.
06:18So the first two, dot and dot dot, are directories.
06:21This is a directory and the parent directory is a directory.
06:24So it didn't try an output anything there. Instead this puts happened and
06:27it just did a simple return.
06:30This though was a file.
06:31It's an invisible file, but it's actually a file.
06:33So we did read from it, we pulled its first line back, then accessing_files,
06:37we got its first line, and so on.
06:39So every single one of those files now we pulled back the first line.
06:42So it shows how you can loop through and work with all these directory entries.
06:46Now it's also possible to open up a directory object to instantiate it, or to do
06:51open the same way that we did file open here, but doesn't really not much point
06:56to doing it that way, because once you get inside, really all you can do is work
06:59with the entries anyway.
07:00So you might as well just go ahead and use this class method on the directory class,
07:04and because so often we want to loop through all of those, because that
07:08such a common procedure,
07:10we also have Dir.foreach, and that's a shortcut to just say take all of the
07:14entries and loop through each one.
07:17We'll say entry then we'll just say puts entry. There it is.
07:21It just output the list of entries.
07:24Making and deleting directories is just as easy.
07:26Let's say Dir.mkdir and then let's say temp_directory, here we are.
07:37So it created a directory. Let's take a look.
07:39Here it is, temp_directory, and then we can just go back when we're ready and
07:43delete it with delete.
07:49Delete temp_directory.
07:50Sure enough, there it is. It's gone.
07:52Now in order for that to delete to succeed, not only do we have to have write
07:56permissions on the directory that contains it, just like we did when we were
07:59deleting files, also the directory has to be empty.
08:02All right, the directory can't have anything in i, if we are going to delete it,
08:05or it will raise an error.
08:07If you want to get rid of something that has contents, you either need to loop
08:10through and get rid of all those contents first, and then delete the directory,
08:14or that file utilities class that we looked at earlier.
08:17The one that we looked at in the renaming and deleting files movie.
08:21You can use file utilities and it has some removal features that will let you
08:25remove the directory, and force it to remove even if it has contents.
08:30So if you really need that functionality, you can go there.
08:32By now you should have a good understanding of both files and directories and
08:36feel very comfortable working with the file system from Ruby.
Collapse this transcript
9. Ruby Project: Creating the Food Finder
Project overview
00:01Now that you've mastered the essentials of the Ruby programming language, I want
00:04us to apply those techniques to a real world project.
00:07Our goal will be to successfully use the right Ruby techniques to write some smart code,
00:11and not only will you be able to get experience that will reinforce the
00:14lessons that we've covered so far, it will also give me an opportunity to make
00:17some points about the best practices you should use in your own Ruby projects.
00:21Now the project we'll be creating is something I call the Food Finder.
00:24Let's take a moment to get an overview of the project.
00:26Simply put the Food Finder is going to be a little Ruby program that will allow
00:30us to find the food that we're in the mood for.
00:33So we'll be able to consult a list of restaurants and find the restaurant that
00:37would be right for us, either to go out to tonight or to order in from,
00:41something like that.
00:42So if we were to make a list of the requirements for the project, it would be
00:45that it's a Ruby program launch from the command line.
00:47It's going to serve as a Rolodex of our favorite restaurants and it's going to
00:50do that by saving those restaurants into a text file.
00:54The program will allow user interaction.
00:56It's not going to just simply output a list to us.
00:59We are going to be able to actually interact with it, ask it questions, look for
01:03one kind of restaurant, then look for another kind of restaurant perhaps.
01:05We'll be able to list out restaurants.
01:07It will give us the name, the cuisine, and the price.
01:10You can certainly add more attributes to it, but we are just going to be
01:13sticking with those three to keep it simple.
01:14It will also be sortable by those three attributes as well.
01:17And we'll of course need to be able to add restaurants to the list, and finally
01:21be able to find restaurants by keyword.
01:24So those are the goals we're going to hope to accomplish for the next several chapters.
01:28Now we won't be creating this project inside our ruby_sandbox anymore.
01:31I am going to create a new folder for it that we'll be working in.
01:33You can put that folder anywhere you like, just somewhere where you can find it easily.
01:37I am going to have mine on my desktop, and I have just called it food_finder and
01:41to start with I've just put a folder in there and they are called lib.
01:44Lib is short for library.
01:45It's a common practice inside Ruby programs to call all of the files that will
01:49be in your library, lib.
01:51I think the best way for you to have an understanding of where we're headed with
01:54this project is for me to show you a demonstration of the final result.
01:58So from the command line I am just going to launch the program and you'll see
02:02that it comes up with some introductory text and it tells me here are the
02:05actions that you're able to perform.
02:07So let's try the first one.
02:08Let's try list. It lists out the restaurants.
02:11So it has three columns, Name, Cuisine, and Price, all nicely formatted.
02:15It also gives me a note that says I can sort using list cuisine or list by cuisine.
02:21Let's try a list by cuisine and sure enough.
02:25It sorted those by making cuisine go in alphabetical order.
02:28Let's try a list by price.
02:30Now it sorted the prices, and it put the prices into ascending order.
02:35Let's try the second action there. We have got find.
02:37So let's try find and let's see what we get back, and it says find a restaurant.
02:40Find using a key phrase to search the restaurant list.
02:43So find tamale, find Mexican or just find mex. Let's try that.
02:47Find tamale, I got back Hot Tamale.
02:51Let's try find pita.
02:52I got back fast food.
02:54Let's try find mex. I got back to the Mexican again, Hot Tamale.
02:59Let's try find 20. I got like all restaurants that are under $20.
03:05That's what they gave me.
03:06Let's try the add now, so we should be able to add a new restaurant to
03:09our restaurant finder.
03:10We've just gone to some fabulous place that we loved and let's say that this
03:14is called the Paradise Cafe and the Cuisine type we'll just say Snack, and
03:20Average price is $5.
03:23So there it is, Restaurant Added.
03:24Let's see if it's added. List.
03:25Sure enough there it is.
03:26Paradise Cafe pops up in the middle of the list.
03:28It's being alphabetized by name by default.
03:31We could also do list by price again, and we'll see it at the top or we can
03:35do our find for paradise and we'll see just the Paradise Cafe, if we want to find it again.
03:40Last of all quit, and quit says Goodbye and Bon Appetit.
03:44So that's a quick tour of what the finished product is going to look like.
03:48Now we're going to see how to actually go about creating that using the skills
03:51that you have already learned in Ruby.
Collapse this transcript
Application paths
00:00Most times when you are starting a new Ruby application, one of the first things
00:04you want to do is establish your application paths.
00:07Essentially you are telling your application, figure out where you were located
00:11inside the file system at this point in time, and then we will be able to use
00:15that path as a basis for any relative paths that need to load in other files,
00:19either for requiring them or for reading and writing to them.
00:22Inside my food_finder project folder I've gone ahead and added a couple of things.
00:26I have got my lib folder,
00:27which is my library for different classes of objects.
00:30and I've got a starting class here, guide.rb, which is empty.
00:33There is absolutely nothing in there.
00:35It's just a placeholder file for now.
00:36And then I have got in init.rb. init is short for initialize and init.rb is
00:41sort of a Ruby convention that this is the starting point of our application.
00:45This is what we will use to launch it.
00:47Now you don't have to follow that convention if you don't want. You can call
00:50this food_finder.rb, or you can call it launch.rb.
00:53But the convention is init.rb and it makes it easy for other people to know,
00:56hey, this is the file that really kicks things off and get things started.
01:00So we are going to use that convention for our program as well.
01:02So we have got some comments at the top reminding you that this is how you get
01:06started, that you launch it from this file, and then I'll define my application path.
01:10And this should look familiar to you. All I am doing is taking a constant called
01:13APP_ROOT, and I'm setting the current directory of this file, init.rb.
01:18That's where my application resides.
01:21That's the folder I'm in.
01:22That's food_finder, wherever that happens to be.
01:25Now I have the ability to locate other files.
01:28For example, if we want to require the guide file, we can say
01:30require, APP_ROOT/lib/guide.
01:32Now that is a full absolute path now, not a relative path, right?
01:38What we were able to do is get an absolute path here for APP_ROOT, so now,
01:43everything we say after that relative to the APP_ROOT is an absolute path as well.
01:47So this will work, we can launch our init.rb, we will get no response back,
01:52because we aren't actually doing anything besides setting these values and
01:55requiring that empty file.
01:57But before we go on, I do want to show you a couple of other techniques here,
02:00including one that we haven't talked about before.
02:03So we have seen that we can require it this way.
02:05Let's comment that line out, and let's do a different require.
02:09We saw that we could use file join, and we saw that that could be a little
02:12bit of a better way to do it, because it will use the separators based on the operating system.
02:17And we can use guide.rb or we can just do the same thing and leave the rb off,
02:22and it will still know where we are.
02:23So either of those will work for us.
02:25I am just going to comment that one out.
02:27and I will go ahead and comment that one out as well.
02:29Those would be slightly superior to the first way that we did it.
02:32An even better way uses a technique that we haven't seen yet.
02:35It's a little bit advanced, so I don't want to go into great depth about it.
02:38But we can use the dollar sign colon variable that's a very strange looking
02:43variable name, but it is a special Ruby variable.
02:45It works a lot like this File does, File with the two underscores on either side.
02:50It's a special magic variable inside Ruby.
02:52And what it does is it contains an array of all the folders that Ruby will look
02:59in to find the files that we've asked for.
03:01Up here we were asking for a full absolute path, but if we could tell Ruby about
03:07different folders by putting them in this array, we wouldn't have to give it an
03:11absolute path anymore.
03:12It would check different places for us.
03:15So the most common way that you do this is you use unshift.
03:18That is what's going to append whatever we want at the beginning, and then we
03:23would put something like this in there.
03:25Let's go ahead and copy this for now.
03:27So File.join but we don't want to tell it a specific file.
03:30What we are telling it is lib.
03:32That's the folder I want you to look in for stuff.
03:35And now that we've added to that list of standard Ruby paths, now we are able to
03:38say require and just guide, require 'guide'.
03:42So let's go ahead just to make sure that this is all working.
03:45Let's go to our command line. I am already inside my food finder. You want to
03:48navigate to that folder or else you want to provide a longer path to get there.
03:52If I just say Ruby and then init.rb, and of course we didn't get any results back,
03:58because all we did was that initialization, and then the file was empty.
04:02Once it actually required the file, it didn't do anything beyond that.
04:04We are going to need to actually define that guide class, and then instantiate it,
04:09and have it do some work for us.
04:10Let's see how to do that next.
Collapse this transcript
Guide class
00:00In this movie we are going to see how to create the guide class for our
00:03Food Finder project.
00:04And the guide class really is going to be the heart of the food finder, because
00:08in that init.rb file, we are going to instantiate the guide class.
00:12We are going to create a new guide, right, a new instance of the guidebook.
00:15And then we will tell that guidebook, hey, guidebook take over, and at that point
00:18the guide class will take over, and it will handle all of the user input,
00:22and do all the processing of the actions that have been asked for, and handle
00:26the user output as well.
00:27So really the guide class is going to be the controller class. It is going to
00:30control what's going on.
00:32To start out with, we will just outline the features that we think it's going to have,
00:35and then over time we can come back and fill those in.
00:38So I have already got a placeholder for my guide.rb inside the lib folder and
00:42I have gone ahead and just given it the class declaration of guides, just to get us started.
00:46So the first thing we are going to want to do is initialize this object.
00:49What do we need to do to initialize it and get things off to the right start?
00:53Well, it occurs to me that the guide needs to know where the restaurant file is
00:57that we are going to store all these restaurants.
00:59We could simply hard code that value in at some point, say well, you know what.
01:02It's always going to be in the same location relative to APP_ROOT or
01:06relative to the guide.
01:08Instead of doing that though, I think because we will make our classes more
01:11general and a little bit reusable, I think it's better if we actually pass in
01:15the path to the file as an argument. That will then allow us to have
01:19different files potentially.
01:20We could have a guide that's for Dallas and a guide that's for Seattle, let's say.
01:24So, I think that amount of flexibility could potentially be very useful for us.
01:27Now once we actually pass in that path, there are going to be couple of things
01:30we will just comment for now.
01:32We want to locate the restaurant text file that's at that path, or if we
01:35can't locate it, we want to create a new file, and if the create fails then
01:39we'll just exit, maybe there was a permissions problem, maybe we weren't able to create it.
01:43So we want to keep that step in mind.
01:45So once we have initialized our guide object, there might be some other
01:48configuration and things that we want to do, but ultimately what we want to do
01:51is launch it and say, "all right, guide, here you go, take over and run."
01:56So I've given it the launch method and I've given it an exclamation point at the end,
02:00just to sort of make it clear that this is a real strong and powerful
02:03method that does a lot of stuff. That's our exclamation point, just sort of says
02:06it's sort of turbocharged.
02:07Now the launch method will attempt a couple of steps. It will give an
02:10introduction that just says welcome to the food finder, here's how you get
02:14started, something like that.
02:16And after that it will go into a action loop and it's going to ask for the user
02:20input, what do you want to do?
02:21and you will have the choice to input list, find, add or quit.
02:25And then we'll do that action, and then as soon as we have done it,
02:28then we are ready to accept the new response, right?
02:30So we listed all the restaurants and then we say, "right, now what you want to do?"
02:32And the user says, "I want to add something."
02:34Okay, well, once we added them we say okay, and now what do you want to do?
02:37We want to list it again.
02:38So it will just be an action loop that will keep going until the user quits and
02:42then when the user finally quits, then we will have some kind of a conclusion
02:45where we will actually just say goodbye.
02:47Now the introduction and the conclusion are just text.
02:50So let's go ahead and just paste those in for now.
02:52You can put in whatever you like. I've just got something that says 'Welcome to
02:55the Food Finder, this is an interactive guide to help you find the food you crave'
02:58and then when they finally leave, it just says 'Goodbye and Bon Appetit!'
03:01So we can now uncomment introduction and conclusion, and those are actually our
03:04method names, right?
03:05So it's going to perform this method and then call this method, right, on this class.
03:11So let's go ahead and try all of this.
03:12Obviously we are still missing a lot of this functionality for finding the file,
03:15and for the action loop.
03:17So the next step of course after we define the class is to go into init.rb,
03:20and get things started.
03:22So let's go ahead and say guide = Guide.new, and we will tell it where the files
03:28is going to be, even though we don't have that functionality built in there,
03:30let's go ahead and put this in.
03:32So the file is going to be called restaurants.txt, create a new guide, and
03:36once you do, guide.launch!, take it away.
03:39Now at this point our init.rb file is done.
03:43That's just going to bring up a new guide instance and get it started and
03:46the guide is going to do the rest.
03:48So we can save that and let's go to our command line and just try it and I am
03:51already inside my food_finder folder, you want to navigate there, ruby init.rb.
03:57So there we go, we get the introduction, and then we get the conclusion.
04:00We don't get anything between.
04:01It didn't do any kind of file checking for us, or anything like that.
04:04We will still have to write that but now we know that our Ruby program is at least started.
04:09All right, we have a class defined.
04:10It doesn't do much, but it does bring it up and launch it for us.
Collapse this transcript
Restaurant class
00:00So far we sketched out our guide class, and we have been able to instantiate it
00:04and launch it, but it doesn't actually do much.
00:06So we need to start going back into those methods and fleshing them out.
00:09And I want to start with the initialize method.
00:11if you all remember, the initialize method in the guide takes a path that we
00:14sent them into it, and tries to find a file located at that path.
00:18If it can't find it, it tries to create it.
00:20Now we could just put that functionality right there in the initialize method.
00:24But that's not the best option.
00:25It's not as object-oriented as it could be.
00:28Instead, it's going to be much better to have a restaurant class and put all of
00:32the functionality of dealing with that data file in the restaurant class.
00:35So I have gone ahead and started the restaurant class.
00:38Let's open that up.
00:39It's in restaurant.rb in the lib folder, and it is just a real simple class definition.
00:44Notice I have got a class variable here for file path, so we don't need an
00:48instance to have the file path, and I'll start it out equal to nil.
00:51Then I have got three class methods and we know their class methods, because
00:54they have self at the beginning of them.
00:56The first is file_exists.
00:58So the restaurant class should know whether it's file exists or not. If not,
01:02they will know how to create the file.
01:04And then the last class method will be, that it will be able to look in the file
01:07and read the file, and after it's done reading, it will return instances of the
01:12restaurant, making each name, cuisine and price into an actual instance.
01:17So those are the class methods we are going to be dealing with.
01:19Let's just push that aside for a second and let's open up the guide class, and
01:23let's take a look at this initialize method here.
01:25So locate the restaurant text file at the path.
01:27Well, we are going to be talking to the restaurant class now, so we need to say
01:31well, restaurant class, restaurant, set your file path equal to path.
01:36Restaurant.file path=path.
01:37There's two important things here.
01:39The first is whenever we call another class its a good idea to require that class,
01:45because it's now considered a dependency, we want to make sure that
01:48class has been loaded in before this class. Not just does it exist, but will it be loaded in?
01:55And it's be loaded in early enough that we can start talking about it.
01:58Now notice that I'm not providing a full absolute path here.
02:01That's because remember earlier, I told that init.rb file where it could find
02:06everything that it was looking for.
02:07I would gave it that lib folder as a path.
02:09So the first place it will check for restaurant.rb is in that lib folder.
02:13Okay, so back to our initialize method. Do you remember what the problem with
02:16file path equals is? Hopefully you do.
02:19File path, the class variable, is not accessible from outside of the class.
02:24Instead we need to have a setter method, self.filepath= and then whatever path
02:31will make it nil by default, and this will now be a setter method that will
02:35allow us to call it from outside the class.
02:37All right, we don't have the ability to call the attr things for class methods,
02:42right, just for instance methods.
02:44Instead we have to write it out in full.
02:46That's okay, because then we will say filepath=and we could just say its equal
02:49to path, but I am going to actually say File.join (APP_ROOT) with the path.
02:56Now that does assume that the path will always have to be relative to the app root,
03:02but that's fine.
03:03That's a restriction I am comfortable making.
03:05Otherwise, if we wanted to allow it to be a file somewhere else, we could
03:08require them to send in an absolute path instead, or we could check and see does
03:12the path start with a slash or something like that.
03:14But for now I am just going to assume that whatever has been passed in is
03:17relative to the APP_ROOT.
03:18So that will take care for setting file path.
03:20So now let's jump back over to initialize, and let's finish taking care of this.
03:23So, we have now set it. We have would told it where the path ought to be.
03:26Now we have the ability to say hey Restaurant, does that file_exists?
03:32And if it does, then let's just say puts "Found restaurant file" or if not elsif
03:40hey Restaurant, try and create_file.
03:42So see how I am controlling it form the guide class, but the actual work is
03:47being done by the restaurant class.
03:49So if we're able to do that, then let's copy that line and let's say
03:53"Created restaurant file."
03:55Or if neither of those happens, it will just exit, and so we will say puts
04:00"Exiting.\n\n" and finally exit!
04:05Now we haven't talked about that yet.
04:06It's a Ruby method that says okay, no matter where you are, no matter where
04:10you've wandered to inside different classes, abort the script.
04:14Just get out, go back, and just finish up what you're doing, take me back to the command line.
04:19And so that's what it will do. It will just stop.
04:21It doesn't take us back to init.rb to finish up anything there.
04:24It just stops cold, right there in its tracks.
04:27So I think that's going to do a pretty good job on our initialize method.
04:29We can go ahead and try running this.
04:30It's not going to do much for us, but let's go ahead and see what happens.
04:33Ruby init.rb and it comes back and says oops! Exiting.
04:37And the reason why it exited, was because, file_exists was not true and
04:41create_file was not true.
04:43So therefore, it fell to this condition, Exiting.
04:45So we need to write something for file_exists and create_file.
04:47That's what we will do in the next movie.
Collapse this transcript
Accessing the restaurant file
00:00Now that we have our Guide class successfully interacting with our Restaurant class,
00:03we need to give our Restaurant class the methods it needs to interact
00:06with the file system.
00:07We haven't written those methods yet.
00:09That's what we will do in this movie.
00:10Now just as a quick review. Remember in the Guide class we are calling a couple
00:13different of methods on the Restaurant class.
00:15The first is filepath equals, which is no problem, we have already created that.
00:19We also have file_exists with a question mark after it.
00:22We haven't written that method yet, and Restaurant create file.
00:26And notice that I am using them as part of a conditional statement, if then.
00:29So we will also want to be mindful of what return value we give for each of these.
00:32 We want to make sure we return True or False to let it know whether it
00:35succeeded or failed.
00:36So let's jump over to the Restaurant class.
00:39Here is our file_exists method, and let's just make a if statement, if something--
00:44we'll come back to it, return true else return false.
00:48So now let's figure what that condition would be.
00:50Well, the first thing is if file path hasn't been set, well then we can't
00:54determine if the file exists.
00:55So might as well just return false at that point.
00:57So first we need if filepath.
00:59Now we couldn't say if filepath is not nil, but there is no reason to do that.
01:03If this value is nil, then it hasn't been set, and that will be equal to the Boolean false.
01:08But we don't just need to have is set; we also need to check and make sure
01:11that the file_exists.
01:14Does the file_exists at filepath?
01:17So this will check and see has it been set and when you go to the file system,
01:21is the file actually there.
01:22That's a good check for file_exists.
01:24Now we could also check for whether the file is readable, writable, right?
01:28Those aren't bad things to test for.
01:30If we did, we probably would want to rename the method something else though,
01:32because file_exists, really is just does it exist?
01:35I mean, it doesn't say anything more than that. Whether the file is actually usable.
01:39So let's actually create a new method.
01:41We won't end up using this for now, but just to illustrate the point, file
01:45usable, and I want to show you a different technique for writing these
01:48if-then statements, because this is a very common sort of paradigm in
01:52programming, especially in Ruby.
01:54So we can say return false unless filepath, return false unless file.exists.
02:04And we can just do a series of these, all the reasons that it might fail, and
02:08let's do return false, unless file.readable at filepath.
02:15And I'll just do one more. I'll copy it. If the file is writable.
02:19So those are all the reasons it might fail, is the file useable or not, and
02:22finally if it passes all of those, return true.
02:26So the main reason I wanted to create this method was to show you that a) it's
02:29not a bad idea to check if the file is readable and writeable, but b) to show
02:33you this structure, return false unless, return false unless. These could be If
02:37statements, it doesn't matter.
02:38The main point is they are all these steps along the way where it might fail.
02:42But if it passes each and every one of those, then the last thing is that
02:45it will return true.
02:47So this is a very common way to write these kinds of Boolean tests, instead of
02:51trying to write If-then statements.
02:53Now that we have written this new better method, file usable, let's actually use that instead.
02:57Let's switch back over here from file _exists to just make it file_usable.
03:01We will use that from now on.
03:04So I'll leave file_exists in here, just so we have it for reference, but we are
03:07going to be using file_usable.
03:08Let's look at create_file.
03:09This is something very basic from where we talked about working with the
03:12operating system. file.open and then filepath, that tells us where it is.
03:17We are going to open it in write mode, and we could provide a code block here, right?
03:21That's how we have seen open in the past, but we don't have to.
03:23If we do that, it will just create the file if it doesn't exist.
03:26So we can say create the file, and let's actually say unless file_exists, then create it.
03:33Now if it does exists, it's no big deal to open it up with write access and then
03:37close it again right away.
03:38That's what happens here, there's no problem.
03:40The one thing we want to be sure though is that we return whether or not
03:44the file is usable.
03:46So at the end of all that, is the file usable?
03:49That's what we are going to return as a Boolean, to make sure that the file we
03:52just created is going to be usable, and we'll pass our Boolean test here.
03:56So let's try all this now.
03:57Let's just go to our command line.
03:59I am already inside my food_finder, so ruby init.rb, and there it is.
04:04It says created restaurant file.
04:05It said, "there wasn't a restaurant file, let me create one," and sure enough
04:08here is that file, restaurants.txt.
04:10You'll find that there's nothing inside of it.
04:12It just opened it and closed there right away, but it did create the file for us.
04:15And if we come back and run it a second time, it says found restaurant file.
04:19So that works as well. We were able to both create it at the first time and
04:22then find it on subsequent attempts.
Collapse this transcript
Handling input in the action loop
00:00So we are off to a good start with our guide at this point and our
00:02initialization routine is basically done.
00:04But what we don't have is any kind of interactivity in our Food Finder and
00:08that's what we are going to work on next.
00:09So I will just open up the guide.rb file and the initialize method is what we
00:14have been working on so far.
00:15We can now call that done. We have really written it.
00:17It is interacting with the Restaurant class and the Restaurant class is handling
00:20everything appropriately.
00:21I am going to use a feature of TextMate to just fold up that initialize method
00:25and I can do the same thing for the introduction and conclusion, because we are
00:27basically done with those two.
00:29But this launch method here has this action loop and we need to tackle that now.
00:34So what do we want to do?
00:35That's what we want to ask the user.
00:37We want to ask the user to give us some feedback.
00:40Well, we know how to do that.
00:41We have learned how to take user input before.
00:43I am going to give the user a prompt first of all and we will put a space
00:46after it and then right after we print the prompt, then we want to do
00:49user_response = gets.chomp.
00:53Remember how to do that?
00:55So it is going to chop off the line return or whatever they give us, but it will
00:58then wait for them to give us a response.
01:01Then we want to do whatever action they give us.
01:04So we will say do_action(user_response) and we will have a method then called do action.
01:11Let's put that right here with def do_action.
01:16So we will need to pass in the action as a parameter to that.
01:20We will come back to that method in a moment.
01:22And then after we do that action we want to loop. We want to do it again.
01:26So let's write a loop, loop do and then let's indent all of these all the way
01:33down here and finally end.
01:37So that will just loop through and it will just keep going, keep going and just
01:40looping asking for the user response every time.
01:42It doesn't get us out of the loop though.
01:43There is no way for us to quit.
01:45Now, we could put something right here that would say break if user_response == quit.
01:54That would work.
01:56And even better way though I think is to go ahead and keep all of our actions
01:59including quit grouped together, so that we will do the action quit and we will
02:03get back to the result of that action.
02:06So if the result that comes back from passing in that string quit to do action,
02:12if that result tells us to quit, then we quit.
02:15And so instead of passing the word quit, I am actually going to just pass the symbol quit.
02:18So if the result that comes back is the symbol quit, then we know we need to quit.
02:23So let's jump down here to do action and write that.
02:26The action that we pass in will be different.
02:28So we want to have different response based on what those actions are.
02:31But we know that they will be ahead of time.
02:32It's either list, find, add, or quit.
02:34Those are the four actions we are going to let them do.
02:36So let's have the case statement.
02:39So case action and then we can say when they pass us list, then puts Listing... for now.
02:48We will come back and actually do the action a little bit later.
02:51For now we are just going to have some kind of response. So Finding...
02:58and when they have told us to add, we will do puts Adding...
03:07and finally when quit and we know what quit needs to do.
03:12Quit is going to return the symbol quit.
03:15Then last of all let's do else puts and a line return.
03:20I don't understand that command.
03:24So there we go, so that will-- and then end at the end.
03:28So now we have nice case statement that just handles the action.
03:31It says okay, take that action, if they gave us list, then do the list.
03:35If they gave us find, then we are going to do the finding.
03:37If they gave us add, we will do the adding.
03:38If they gave us quit, just return the symbol quit, which gets caught by result
03:43and says hey, let's break out of the loop now.
03:46So let's go ahead and try this.
03:47I will just save it.
03:48Let's jump over here to the Terminal and let's try ruby init.rb.
03:54Welcome to the Food Finder.
03:55So now it's waiting for me. List, Listing...,
03:58find, Finding..., add, Adding....
04:01Let's try something garbage. I don't understand that command.
04:05And let's try then finally quit, which sends the symbol quit and breaks us out
04:09of the loop and once it breaks us out of the loop,
04:12that gives us the conclusion and we then wrap things up.
04:15So this works, this is great.
04:18I think that loop is not used that often in Ruby.
04:21Usually, there is a better way.
04:22If you find yourself just doing a simple loop, there is probably a better way to
04:26write it in most cases.
04:28So in this case what we actually could do instead, what I think is a better
04:31way to do it is until result is equal to quit and then we just have to
04:37initialize result up here.
04:38So result equals let's just say nil to start with.
04:42So result starts out being nil.
04:43Until it is equal to quit, which it's not the first time, then we do the loop.
04:47We don't need this break anymore.
04:49Here we can just take that out.
04:52So we go through the loop.
04:53Is result now equal to quit?
04:55If so, then we break out of the loop, because the until statement told us to.
05:00So it is little bit cleaner, a little bit more succinct and a little bit more Ruby-like.
05:04I think that most Ruby programmers would tend to program it this way instead
05:07of using that loop.
05:08Loops are just a little bit clunky.
05:11The one last footnote that I want to give you about this
05:13now that we have a loop of user input is that if you need to break out of it, if
05:16you wrote something incorrectly and you are stuck in an infinite loop, from the
05:19command line you should be able to use Ctrl+C. That's hold down the Ctrl key and
05:24press C and that should exit out of the program.
05:26It should force it to quit.
05:28So that's a very useful keyboard command to know.
Collapse this transcript
Limiting input
00:00In the last movie we enabled our Guide class to be able to handle user input.
00:04In this movie, I'd like to improve that a little further by restricting the data
00:07that will allow the user to give us.
00:09The thing that I am mostly concerned about is that we are accepting any response
00:12from the user here and passing it right away off to the action.
00:16And the action is handling it appropriately.
00:18The action, if it doesn't fit one of these categories, comes up and says,
00:20"oh! I don't understand that command."
00:23But I think it's better software design if we actually trap it before we try and do the action.
00:28Let's make sure we got valid input before we run off and try and do it.
00:32The other one works.
00:33There's no reason that that's wrong.
00:35You can do it that way, but I think it's a slight improvement and it will also
00:38give us a place to make some more improvements a little later on.
00:40So, let's go ahead and make that change. What I want to do is make a new
00:44method called get action, and I am just going to right now move these two
00:49lines down into get_action and that means that these I'll just take away, and
00:56instead of being the user_response, now we will say, well the action is going
00:59to be equal to get_action.
01:02And then we'll just go ahead and do action.
01:05We'll pass in the action here.
01:06So, at the end of this, what we want to do is return the action, which means
01:13that of course, my action has to be equal to my user_response.
01:18Now, that probably seems a little bit redundant, but that's because what I have
01:23in mind here is that we can actually make a quick improvement to the
01:25user_response by saying well let's actually take the response and downcase it,
01:29and strip any spaces out of it.
01:31So, already we've improved what the user gave us.
01:33We'll make sure that if they gave us all capital, they have their Caps Lock key on,
01:36and they type list,
01:37it will still work, because it will be downcase before we would return it.
01:40But the big improvement that I want to make is that I want this to now be inside a loop.
01:45So that it checks to see whether or not this is a valid action before it
01:51actually returns it and says let's get started.
01:53So, we need a way that keeps track of what the valid actions are.
01:56So, I am going to come up here at the top of the Guide, and I'm going to create
01:59a class inside the class.
02:01Now this is not strictly necessary to have a full class in here, but I am
02:05going to call it Config, and that's where I am going to put configuration
02:07information about the Guide.
02:09Having a separate class can be a nice way to be able to group together some of
02:12these attributes and methods, but it also just illustrates the fact that you can
02:16have a class inside of class and that's mainly what I want to show you.
02:19So, it's a little bit overkill in this case, but it does make the point.
02:22So, let's say actions =, and the actions we are going to allow are list, and
02:27find, and add, and quit.
02:31Those are the things that they are allowed to do.
02:33Now, we'll need a way to be able to read that, self.actions.
02:37Remember it's not accessible from outside the class.
02:40And I'll use my semicolon, so I'll just put it all on one line, just return the action.
02:45So, notice that I have just got semicolons here that let me, instead of breaking
02:49it up onto several lines, I can just a one quick line, here is a reader method
02:54that will read back those.
02:55So, now down here I can actually ask for that.
02:57I can say Guide::Config.actions and that will return that value.
03:05So, does it include whatever action we have been given? Well until it does,
03:12we are going to loop.
03:17So, see what I have done.
03:18It's a loop that's says all right, let's keep going through, every time
03:21we'll loop through and see does the action that we've been given, is it one of these actions?
03:25If so, we can return it. If not then, we have got to go through the loop again.
03:30So, let's start out with action = nil, so that it has a value the first time
03:35through and that first time it will be equal to nil.
03:37So, the nil is obviously not in that list, so then it will go through again and
03:41again and again, until finally, they give us something that matches and at that
03:45point it will already be down cased and stripped. We'll return it.
03:48I'll just put in a comment here to remind us that that's what it's doing.
03:52One nice thing about doing it this way is that now we have the opportunity
03:54to not just say hey! user, we didn't get good feedback. Instead we can say here are your available actions.
04:01If that list changes and we add a new feature, we add a new action, boom!
04:04It gets added to the list automatically.
04:07So, we'll take that list of actions, we'll just join them together with a comma
04:10and a space between them and so we will have a list, saying what they are.
04:13Now it's a little weird the first time you come there to say it, so we might
04:15some have something like if action, which means the first time when it's nil,
04:19it won't output this list.
04:21It's only if we get a failure.
04:22So, let's just try running all this.
04:24Let's see how all this goes together.
04:26Let's go to the command line and let's run ruby init.rb.
04:31So, here we are, food we crave.
04:33So list, Listing. LIST, Listing. Space space list space space, still works. Listing.
04:40If I now type something that's garbage, it comes back and says oops actions and
04:45it gives me a list of the available actions.
04:46It's a little bit friendly and then finally quit when we are done.
04:50So again, while it's not strictly necessary.
04:52I think that it is better to pull all this off into its own get_action, because
04:56that gives us a place to add some enhancements in there, and they don't clutter
05:00up this launch method, right?
05:01get_action contains all the information it needs to know about how to get the action,
05:05and that's where we'll make sure that the input is valid, before we
05:10ask do_action to do what it knows how to do best, which is to actually perform that action.
Collapse this transcript
Adding restaurants
00:00Now that we are handling the user input well, we need to start responding to
00:03that input with some meaningful results.
00:05The actions inside our food finder.
00:07And I am going to start out with the add restaurant action, because we can't
00:11really list or find restaurants until we have some.
00:14So, here we are going to concentrate on getting the information about the
00:16restaurant, and then saving it to that restaurant's text file.
00:19Inside the guide.rb file we have been working with, we already have a do_action,
00:23that takes a string, and if that string is equal to add, then it's going to do
00:28our add action, right.
00:29Well, we could put all the code for that right here inside the case statement,
00:33but I think it's better to use this as sort of a signpost, telling us what
00:36method we are to call from here, and then we'll have one called add.
00:40And then I'll make a new method down here, just call it add, and so when it's
00:45equal to add, we'll call the method add.
00:47So, all of this will get executed.
00:49So, what do we want to do?
00:50Well, the first thing I am going to do is just output something that says all right,
00:53we are adding a restaurant.
00:54It's sort of like a title. Then we want to actually create the restaurant,
00:58give it its values, its correct attributes, and save it.
01:02Those are the steps we are going to go about.
01:03Well, we know how to create a new restaurant. We create an instance of
01:06the object restaurant.
01:07restaurant = Restaurant.new.
01:12Now in order to add attributes to it, we need to have instance variables.
01:17Those are the attributes.
01:18So, if we come back over here to restaurant, we have written lots of class
01:21methods so far, self.filepath, self.file_exists.
01:24This is a class variable. We don't have anything for the instances.
01:28So, in order do that let's create attr_ accessor, so it can both read and write
01:34for name, cuisine, and price.
01:39You can add others if you want. I am just going to keep it simple by
01:41having those three.
01:42So, let's jump back over to our guide now, and we can start to put in values for that.
01:46So, we are going to have restaurant.name = and restaurant.cuisine =
01:55and restaurant.price =.
01:58So, in order to fill those out, we need user interaction, right?
02:02We know how to do that already. What we want to do is give the users some kind
02:05of a prompt first of all.
02:06So, let's say print Restaurant name: ,
02:11and then that will then stop and prompt them using gets.chomp.strip.
02:17So, that will take any spaces out of it at the end.
02:19I am going to use that all three times, but instead of Restaurant name, we are
02:23going to then ask for the Cuisine Type, and let's ask it for the price.
02:32We'll call it Average price, so it's clear that that's what we are
02:34really looking for.
02:35It's just a rough estimate, Average price.
02:37Let me go ahead and make that lowercase as well so it matches.
02:42Okay so now we've got an instance and we've given that instance attribute its values.
02:47Great! What's our next step?
02:48We need to save it to that file, so how we are going to are going to go about doing that?
02:51Well, saving it, what it really means is appending this data to the file, so we
02:57can read it back later.
02:58So that's what we are going to do.
03:00I am going to do it using restaurant.save.
03:03We'll have to write that method.
03:04That's going to be an instance method on the restaurant class that we'll save.
03:08And if the save succeeds, we'll return one thing and if it fails we'll
03:11return something else.
03:12So, if restaurant saves then let's just say puts and I'll just put a line return here.
03:18Restaurant Added line return, line return and if it fails, I'll just copy that.
03:28Let's change it to say Error: restaurant not added.
03:36And let's actually change it to be Save Error, so it's clear that's what
03:40we're talking about. Save Error:
03:42Restaurant not added.
03:43That will give us some meaningful results.
03:45Our results of our save we'll need to return true or false.
03:48So, we'll just want to make sure that the end we return either true or false for that.
03:50So, now let's write that Save method.
03:53It's going to be instance method. I like to put my instance methods below my
03:57class methods and I think most Ruby developers do as well.
04:00So, I am going to have all my class methods at the top, then my instance methods.
04:04So, I have got an instance now that needs to be saved. How does it go about saving?
04:07It's going to open up the file and write to it.
04:10So, we need to make sure that that file exists, return false unless file,
04:17actually let's say usable, so we can make sure it's writable.
04:20In the past when we were doing create file for example, we were just using
04:24file_exists and file_usable on their own, just calling those methods, but this was a
04:29class method itself.
04:30Now we are using an instance method.
04:32So, we need to ask the actual class Restaurant.file_usable, all right?
04:38Otherwise it's going to look for an instance method called file_usable.
04:41We need to class method.
04:42So, we have to tell it, hey! you have to ask the class for that.
04:45So, now let's go-ahead and open up the file.
04:47If the file is usable then we didn't return false, then we are going to do a
04:50File.open, and we know where that's going to be located, set filepath, and
04:56we want to append to the end.
04:58So, we are going to be in Append mode that'll put our file pointer at the end of
05:01the file ready to write a new line, and do File and then what are we are going
05:07to actually put in there?
05:08Well, we have this file block variable that we are going to be working with,
05:12and we can tell it puts, and then what do we want to actually put here?
05:16There are a lot of different ways you could do this.
05:18I am going to do it by saying okay, everything I want to input is going to be
05:21inside these brackets and then I am going to do a line return at the end and
05:25what I am going to put in here is going to be an array made up of name,
05:29cuisine, and price.
05:32And then I will just take that array and join it together with tabs.
05:37So, that's the \t for a tab.
05:40And notice I used double quotes in every case so that these get
05:43handled appropriately.
05:44Single quotes would not handle these escaped characters right.
05:47So there we go. That will output a tabbed version of this array.
05:52So, it will be name tab, cuisine tab, price and then a new line return, and that
05:57will be essentially how we'll export a line to the file.
06:00So, then we'll say return true at the end, so that we know that it did succeed.
06:04We did get down there.
06:05Let's try it out, see if it worked.
06:07So, let's go to our command line, ruby init.rb.
06:11Welcome to the Ruby Food Finder.
06:12What do we want to do? We want to add. Restaurant name.
06:15Let's start with Hot Tamale and it is going to be Mexican and the price,
06:22the average price we'll just say is $25.
06:23And it goes back and says Restaurant Added.
06:26Great! Did it actually add it?
06:27Let's just hide these results, so we'll switch here, and let's open up
06:31restaurants.txt and sure enough, there it is. Hot Tamale, there is actually tab
06:35here between it, and a tab here and then a line return.
06:38It's ready on line 2 for me to add another restaurant to it.
06:40So it succeeded. We were able add it.
Collapse this transcript
Refactoring the add action
00:00In the last movie, we successfully coded the add action, and it does exactly
00:04what we would want it to do.
00:05It lets the user input the properties of the restaurant that they want to create
00:09and then it saves them to the restaurant's file.
00:11In this movie though, I want us to look at how we can refactor that action.
00:15If you haven't come in contact with that word refactoring before,
00:18code refactoring means rewriting the code to improve it, to improve its structure,
00:23its readability, maintainability, performance, or its extensibility, being able
00:27to extend it, without modifying behavior or functionality.
00:31So that's what we are going to try and do here.
00:32The end result is it's still going to save it to the file, exactly the same.
00:36But we are going to see how we can improve our code.
00:39At the moment, our add action is creating a new restaurant and then setting all
00:43of these values one by one and then saving it.
00:46That's the behavior I want to change.
00:47Instead of creating an object and adding attributes, I think an improved way
00:51to do it is to add that functionality into the restaurant class, into the initialize method.
00:57So initialize, and it's going to take some arguments. We will make it a empty hash,
01:01in case they don't pass any arguments to us. We will still just go ahead
01:04and do the initialization.
01:05But if we do get a hash, then let's go ahead and set name equal to args and then name.
01:13Now if we don't get a name sent, we will get nil.
01:15Instead of getting nil, I am going to have it default to an empty string because
01:19I would rather have an empty string in the name than I would nil.
01:22We can do the same thing for cuisine.
01:24Cuisine equals args and cuisine and once again and an empty string.
01:31And last of all, price equals args and price.
01:36Now this is a very common pattern that you will see in the creation of
01:39attributes in the initialize method.
01:41We will book for some value in the arguments. If it's not there, then we
01:45default to a default value.
01:46And also, you'll often see these spaces here done so that everything lines
01:51up nice and pretty.
01:52It's up to you if you want to do that or not but that just kind of gives it a
01:56nice clean cut look.
01:57So you will see that in a lot of people's code as well.
01:59So at the end of this, we will create a new object and either all these values
02:03will be sent to empty strings which still could be saved to the database if we
02:06want to tell it to do that.
02:08We could also say well you know what, don't save it unless you have all three values.
02:12We could add something in here that would actually do some validation.
02:15I am not going to do that.
02:16I will leave that at something that you can do, but the save could fail just
02:19because the attributes aren't ready.
02:21But if we are passed those attributes, they'll all get set.
02:23So now, back on this page, we can set up something here and say args, this is a
02:28different args, of course.
02:30This is just going to be a local hash that we'll be working with and for each
02:33of these, we can now say args, and let's put the brackets around it, and we'll make it a symbol.
02:39Right, so in the args name, go ahead and put whatever they give us.
02:43Let's do that for each of these. I'll just copy this and paste it in for
02:48restaurant both times.
02:49We will need our closing square brackets on both of them as well.
02:52So now at the end of this, I have a hash that's ready to pass to Restaurant.new.
02:57So Restaurant.new can move now, it can drop down here, Restaurant.new(args).
03:02So we will just pass in whatever args have got set to the restaurant and then save it.
03:07So that's what refactoring is.
03:08It's very common thing to be refactoring in your code to make
03:11slight improvements.
03:12I think this is slightly better because now we have an initialize method that's
03:16smarter and I think it's a good thing if our objects can gain some intelligence
03:19and be able to have some features and functionality we might reuse other places.
03:23There is more that we can do though.
03:24It bothers me a little bit that we are doing all of this information about
03:28filling out a restaurant in the guide class.
03:31Seems like the guide class isn't the right place for it.
03:33What I would really like to be able to do is just tell the restaurant class to
03:36handle all this data gathering for me.
03:39What I would want to be able to do is to say instead of restaurant here,
03:43let's say restaurant, and I will just copy this line,
03:46Restaurant.build_using_questions, let's call it.
03:50So I am just going to tell the Restaurant, hey, ask the questions you need in
03:53order to build yourself.
03:54And all of this then can be removed.
03:55I am going to cut it, so that I have it still.
03:59It's on my clipboard.
04:00So right now, all I am doing is saying, "hey Restaurant, do your thing and when
04:03you are done, save."
04:06Now let's just jump over here. We are going to need a new method here that will
04:09handle that for us, right.
04:10This is going to be a class method because we are telling the Restaurant class,
04:15build_from_questions.
04:21And I am going to paste everything that we had in the other one in there.
04:24We are going to need to just do a quick check to make sure the code is still
04:27good for us and it's going to set arguments.
04:30It's then going to print the restaurant name.
04:33It's going to get a response.
04:34Then finally, at the end, it's going to just do self.new with the (args), and
04:41we don't need to set it equal to restaurant. We can just return that.
04:44So return the result of creating a new object, a new instance, using these arguments.
04:49Now all that logic is contained inside restaurant.
04:52If we had now other areas of our guide class where we wanted to be able to build
04:57these questions or maybe we would want to be able to reuse this class and have
05:00other classes be able to call it.
05:02It would still have that knowledge about how to go about building a restaurant
05:06instance built into it.
05:08So I am going to save both of those.
05:09Again, the net functionality of this is exactly the same.
05:12We have cleaned up things a bit, we have moved things around but we haven't
05:16changed the functionality.
05:17That's why we consider it refactoring.
05:19So let's try it all out from the command line and make sure everything still
05:22works exactly the way we want and we didn't make any mistakes.
05:25ruby init.rb, here we are. Let's add.
05:29Oh, we have build_using_ questions is not a method.
05:33Why did we not do that?
05:34build_from_questions, ah, using_questions, there we go.
05:38So I did make a mistake.
05:39So now let's go back and try it again, ruby init.rb.
05:42Now here we are, add.
05:43All right, what's the restaurant name?
05:45Let's say Cafe Masala, and that's going to be Indian food.
05:50And the average price, we will say it's $30.
05:52Okay, restaurant added.
05:54Let's just double-check and make sure that that's true.
05:57We'll jump back over here and we'll take a look at our restaurants.txt file, and there it is.
06:01It made a new entry for it.
06:03So it did successfully add it. We didn't change anything. We didn't break any functionality.
06:08We just improved our code in the process.
06:10And that's what refactoring is all about.
Collapse this transcript
Listing restaurants
00:00Now that we have a few restaurants saved on our file, we can now write the list action.
00:04We will actually display the restaurants that are saved, so the user can review them.
00:09The process of starting the action is the same as we did for add. We are
00:12going to just have list here called as a separate method and we are going to
00:15define this method here.
00:17We also created a stub for saved_ restaurants over here as a class method on
00:21restaurant, back at the very beginning.
00:23That's what we want to flush out, right?
00:24That's going to pull up an array of all those saved restaurants.
00:28Then the list can actually go about listing them, right?
00:31So, let's have the list action. We'll just copy this first line from adds, all right.
00:36So, it's going to be Listing restaurants, here we go.
00:42So, that will be the title here of the page, and then we know that we want to do restaurants.
00:48That's going to be equal to ask the Restaurant class to return
00:52the saved_restaurants.
00:54And that will give us an array that we can go on to display.
00:57So, let's go ahead and write that saved_restaurants method and then we'll
01:00worry about the display.
01:01So, the saved_restaurants.
01:03Read the restaurant file, then return the instances of the restaurant.
01:07That's what we want to do.
01:08So, reading the restaurant file, we know how to do that.
01:11That's working with the file system again.
01:12Let's just try out with empty restaurants = and then we are going to read from the file.
01:19If file_usable.
01:23This is a class method, so I'm able to use file_usable without putting the class
01:27name in front of it.
01:28So, if the file is usable, then let's try and return the restaurants.
01:33File is going to be equal to File.new.
01:35I am going to do it using the instantiation of the file technique, instead of
01:39the Open command, you can do either one, filepath, and we are going to be
01:43reading from the file.
01:44So, we'll just declare it as an r. Let's go ahead before we forget and do
01:47file.close that will remind us to close it at the end.
01:50file.each_line, that's the method we'll use.
01:54That will take a block and we'll go through each one of the lines in the file
01:58and it will do something with it.
01:59So, I am going to then say, well, restaurants. The array will be appended with
02:05an instance of my new restaurant.
02:07So, I want to take that line and convert it into a restaurant.
02:10Now, I could do that do that here, so that I had the line ready to go as
02:14attributes I could pass off to new.
02:16I am going to show you a different technique though, which is Restaurant.new.
02:20So I'll create a new instance, no attributes being sent and as soon as I have
02:24the instance, I immediately turn around and ask that empty instance to import
02:29the line, and I'll say line.chomp and that will make sure that we get the line
02:33ending off of there.
02:34Now, let's write a method, actually this is going to be an instance method, so
02:38I'll just drop down here below initialize.
02:42This is an instance method called import_ line and it will take a line as its argument.
02:49Could I've written this as a class method and done it like I did build using questions? absolutely.
02:54I just wanted to show you a different way to do it.
02:55So, you could've condensed this all down to a class method just like we did here,
02:59than then would have passed something into initialize. Instead though,
03:03we are going to create an empty instance, then populate it.
03:07The line itself is tab delimited, right. So line_array = line.split and we'll
03:14split it on those tabs. Now, we'll have an array and each item in the array
03:18will be name, cuisine, and price in that order.
03:21So, once we have that, how do we go about setting all those attributes?
03:24Well, we could do @name = line_array 0.
03:30That would pull in the first value, or we could be even fancier and we could
03:33say .shift and that would pull the first item out into name
03:37and then we could shift again, because the next item at that point would be the cuisine.
03:42But an even slicker way to do it I think, since we just have so few of these,
03:46is to go ahead and use this triple assignment in this case. price. When I provide an array,
03:52this is an array, even though it doesn't look like an array, because I don't
03:55have the square brackets, it is, and I say equals to another array, then it
03:59attempts to assign the values that are in the line_array in 0, 1 and 2 to these
04:03three values, boom, boom, boom.
04:05So, that's a nice way to do it.
04:07At the end, once we are done importing the line, we are going to say return self.
04:12Now, think about why we want to do that.
04:14Why do we want to return the object itself?
04:17Because essentially what we've done is populated it and the result of this whole
04:21operation, creating new returned an object.
04:24It returned the Restaurant instance to us.
04:26import_line also needs to return that same instance, because we need that
04:31instance to go into that array.
04:33Otherwise, if it return let's say true or false, then what we get pushed into
04:37our restaurants, would be true or false, all right?
04:39So, it's important that this whole operation returns an instance.
04:43I want to make sure that you understand that.
04:45So, that will take care of it for us.
04:47That should take the line, put it into the attributes of the object and then
04:51allow us to put the object into restaurants.
04:54The very last thing of course is that we need to return restaurants.
04:58And I'm having the return restaurants outside of file_usable, so that it'll
05:01just return the empty array if the file is not usable. We'll just get back no restaurants.
05:06You could return an errors or something like that.
05:08I am just going to have it say here were no restaurants to be found.
05:11One other consideration that I want to point to you here is that when we are
05:14designing this method, we also have to ask ourselves if we want to get a fresh
05:17copy of these restaurant each time, do we want to go back to the file system and
05:21reload whatever is there?
05:22Or do we want to store these results in a variable, so that they are now booted
05:26one time, and we never need to check again?
05:28In that case, we could turn this into let's say @restaurants, right?
05:31And we could check to see if it had been set already or not.
05:33I am going to have it so that it actually reads every time.
05:35That way maybe if there's more than one person working on this file, or if we
05:39change the file by actually going into the file and typing something, we will
05:43get a fresh copy each and every time.
05:44So, just consider that about this saved_restaurants method.
05:47So, now that we get back an array of restaurants, let's actually output that array.
05:51You should know how to do this.
05:52It should be nice and easy.
05:53We are just going to say restaurants.each do and I'll just abbreviate it as rest.
06:00So, for each restaurant, puts rest.name and then lets put a pipe.
06:06That's the upper right, + rest.cuisine and then let's put another pipe, and
06:15finally, puts rest.price.
06:18Okay now that we have it, let's try it all out.
06:20Let's save it and let's go to our command line.
06:22I am inside the Food Finder, rubyinit.rb, and this time we have already added,
06:27so we can just say list, LISTING RESTAURANTS and there we go.
06:30We get our list of restaurants back.
06:32It went to the file, read them in, turned them into instances, passed them
06:36back as an array to the list action and the list action then went through that
06:39array and output the contents of the array, by calling these attributes named cuisine and price.
06:47In the next movie, we'll take a look at how we can improve this output, so that
06:49it looks a little nicer.
Collapse this transcript
Improving output
00:00In the last movie, we were able to read the restaurants back from the text file
00:03and output them for our user to see, but the output is not that pretty.
00:07In this movie, I want us to explore couple of techniques we can use to make that
00:10output a lot better.
00:11The first thing you'll notice is that I've added a couple of files in.
00:15So these are going to be in the exercise files or I'm going to show them to you
00:18and you can copy them down.
00:19But I've created a new folder called support, and in there is number_helper.rb
00:23and string_extend.rb, and we're going to be using both of those.
00:26I've called it support, because these are just kind of the support files that
00:29will help me with my library.
00:31It doesn't matter really how you organize them.
00:33So let's open up number_helper.
00:35This is a module that we can use as a mix-in into our classes and it
00:40borrows heavily on a method that's inside the Ruby on Rails framework,
00:43called number_to_currency.
00:44So that's what I've called it again.
00:45It's number_to_currency.
00:46We provide a number, and then a set of options, and those options can be the
00:50unit, whether it's a $ sign, by default.
00:52The precision, how many decimal places it should have.
00:55What it should use between the numbers as a delimiter, so 1000 would be 1,000,
01:01and the separator, the decimal separator.
01:03So all of those are configurable.
01:05Notice that the format that we're using to set all of these is the same way that
01:08we did it in the Restaurant class.
01:10Just to quickly walk you through the rest of it, we're going to remove the
01:13separator if we've been told not to use any decimal places.
01:16Then we're going to take the number, and we're going to split it on the decimal.
01:19We're going to turn into a string, split it on the decimal so we have two halves.
01:22The integer half and the decimal half. We'll work with them separately.
01:25The integer half, we're going to loop through, and we're going to insert the
01:28delimiter after every three places.
01:30We're counting backwards is what we're doing.
01:32So we're going just move backwards through it, every three numbers, stop and put
01:36in the delimiter that we need.
01:37For the precision, now the precision is equal to 0, well, then there is no decimal.
01:41We can just have a empty string for our precision decimal.
01:43Otherwise, let's go through and figure out what that decimal ought to be, make
01:47sure it's not nil, and then, make sure it's not too large.
01:50We're taking the string. This bracketed call we're doing on the string is saying
01:54okay, starting at the first letter, return everything up to however much
01:58precision -1, because the count starts at 0.
02:01So that's why we did the -1.
02:02So that makes sure it's not too large. It clips it if it is.
02:06If it's too short, then we want to pad it out.
02:08So if the number we got like was 10.2, and we told the precision was 2,
02:12we need to add an extra 0.
02:14We do that with ljust.
02:16That's Left Justify.
02:18Let's see how that works.
02:19I think that's going to be useful for us in other places as well.
02:21I'll just pop into irb real quick, and let's just say hello, as a string.
02:25If I do ljust, and then tell it a number, let's say 30, and then I provide a
02:32character that I wanted to use to fill in the remaining characters up to 32. See what it does?
02:38Hello, and then however many other characters it takes till I get to a
02:42total length of 30.
02:44Let me show you rjust and I think it will make sense.
02:48Now we've right-justified it and we've filled it in with those extra characters.
02:52Now if we don't specify characters, it gives us spaces, which really makes it
02:56look left-justified and right-justified.
02:57We also have center, which does the same thing.
03:02It just centers it.
03:03So it pads it out so it's exactly the same width, 30 characters every time, but
03:07either left-justifying, right- justifying or centering our string.
03:10We'll make more use of that a little bit.
03:12But for here, what we're doing is we're saying okay, pad out until you get to
03:16the number of precision, pad it with zeros.
03:19So that's what we're using ljust for.
03:20So now we've got four strings.
03:22We just smash them altogether and return them, the unit, the integer,
03:25the separator, and the precise decimal. That does it.
03:28That will give us something that with then we can output, number_to_currency.
03:31So again it's a module, ready to be mixed in.
03:34You can pause the movie if you need to copy that down, or you'll find it in
03:36the exercise files.
03:39Now where do we want to add that to?
03:40Let's go to the Restaurant class, and let's require it here, require
03:45'support/number_helper'.
03:49That'll make sure that we have the code loaded and we're ready to use it.
03:52So let's include it then as a mix-in, NumberHelper.
03:54That's the second step.
03:57Now that functionality is inside the Restaurant class.
04:01So where do we want to use it?
04:02I'm going to make a new method down here called formatted_price, and
04:08formatted_price is just going to return the price, but with formatting.
04:12So number_to_currency, and we can provide different options in the hash as a
04:17second argument, or I can just let the defaults kick in, which is to look like a
04:21number with two decimal places. So I'll save that.
04:24Now, this is an attribute we can call. Just like we can call price, we can call
04:27for its formatted price.
04:29Let's close that up and open up the guide.
04:32Instead of price, now let's ask for formatted_price.
04:37We'll just jump back over to our Terminal and let's try it all out,
04:40ruby init.rb, and list, and there we are.
04:44We now get this formatted_price back.
04:46So that's an improvement.
04:47We saw how rjust and center work.
04:50It seems like we can actually make this look a lot nicer and look a lot more like
04:53a table, if we use those.
04:55So let's quit out of that and let's just jump back over here to list and let's
05:00try and make that look a little better.
05:01For outputting the header, let's center that.
05:04Let's actually take that, I'm going to cut it out, let's center it, but I'm
05:08going to do it via a different method, private method here that I'm going to
05:11call output_action_header, and we'll pass it a bit of text and it will then
05:22take that text and output it, whatever we've asked it to do.
05:25So in this case, Listing restaurants would be the text.
05:31So up here I just have to call output_action_header and then
05:37Listing restaurants.
05:38Right, so that will now call this method, pass this argument and do the exact
05:42same thing that we were doing before. Okay?
05:44I call it output at the beginning. I like to do if it's just really something
05:47that's going to do output for me.
05:48That just sort of reminds me that that's its purpose.
05:52So instead of upcasing the whole thing, I'm going to move that inside in just
05:55up-case the text, and then I also have the ability to apply center to it.
06:01Center, and we're going to give it a width of 60.
06:04So I'll save that, after making it uppercase.
06:06It's just centered within a 60-character space.
06:08Now for the rest of the output here, let's also put it in that 60-character column.
06:12Rather than have you watch me type the new formatting for that, I'm just
06:16going to paste some code in here and then we'll walk through it.
06:19So I'm going to do output_restaurant_table.
06:22If we pass it in a set of restaurants, it auto-output the header.
06:25Here we've got the Name, and then it's going to left-justify that by 30,
06:29the Cuisine, left-justify that by 20, and the Price, left-justify that by 6.
06:33Those numbers altogether plus the spaces are going to add up to 60.
06:38Then I'm going to use the multiplier here to just get 60 dashes to go across in
06:43a row, and then I'll go through each restaurant, and I'll do the same thing.
06:46I'll tell it, all right, let's build up a line.
06:48We're going to now put a space, followed by the name, justified, and then the
06:51cuisine, justified, and then the formatted_price, again justified.
06:55At the end, once we've built up that line, we'll output it.
06:58So that's what I'm doing there and I've also added something here that says
07:01well, let's also output something friendly, if there were no listings found.
07:04Let's just say that the restaurant was empty and then we'll have a line at the end.
07:08Now instead of doing this loop through, we've already got the loop built
07:11into our output method.
07:13So all we have to do is replace all of that with output our restaurant's table.
07:17So it's real clear what we're doing here. We're outputting the action
07:19header, we're getting the restaurants, we're outputting the restaurants, and
07:23I don't need this here.
07:24So let's try running this.
07:25We'll go back to our Terminal, ruby init.rb, here we are, list, there we are.
07:30Look how much nicer that looks.
07:32Now we've got a nice centered title, we've got columns that make it feel like
07:35it's a table, much better output.
07:38I'll quit out of it again.
07:39The last thing I want to show you is this string_extend.rb that I've written.
07:43This is a very simple class.
07:45It opens up the core Ruby string class and adds another method to it.
07:50We saw how we could do that earlier.
07:51I wanted to make use of it so you could see it.
07:53I created something called titleize. Ruby has a capitalize method that will just
07:58capitalize the first word.
07:59It's like capitalizing the first word of a sentence.
08:01But we don't have a way to capitalize the first letter of every word.
08:05So what I've done is said, all right, take a string, split it up on the spaces.
08:09That will turn into an array, go through each of those and capitalize each word
08:13that you come across, and then rejoin it back together with the spaces.
08:17So that will then capitalize every single word.
08:21So this will add to the core string class. We don't include it as a module,
08:25right, we're not going to have to mix it in or anything, but we do have to make
08:29sure that it's loaded.
08:30So we do up here at the top of the Guide class, if we're going to make use of it,
08:33we want to say require 'support/string_extend'.
08:40That will make sure that it's loaded, it will get added to the class, and now we
08:43can make use of that.
08:44So let's do that on our output restaurant table.
08:47Let's go ahead and say that the name will get titleize and the cuisine
08:51should also get titleize.
08:52So those are now just methods on a string that we can call.
08:57Let's try it one last time, ruby init.rb, list, and now it's titleized.
09:03Let's try add, just so that we can add restaurant name and let's put this one in
09:07lowercase, pita pocket would be the restaurant, and let's just say it's going to
09:12be fast food, and the price will be $10.
09:17Restaurant added, now let's list it.
09:19Notice that Pita Pocket got capitalized. Fast Food also.
09:23Each of the words got capitalized as well.
09:25The one other thing we don't want to forget to do is now that we have this nice
09:27output_action_header method, we want to make use of it.
09:30So if we come up to add, we can actually use it here on the action header.
09:35Right, let's put the parentheses all the way around it. We don't need to do the
09:39upcasing anymore, and we don't need to do that. We just have to pass it a string
09:43and it will take care of the rest.
09:45So this output_action_header will give us a nice consistent way to output the
09:49header of every single one of our actions.
09:51So, I think that the formatting improvements we made really helped.
09:54It starts to give our program a more of a professional polished feel to it.
09:57And in the process, you were able to see a variety of techniques that we can use,
10:00either by using mix-ins, by extending Ruby's core classes, or by using some
10:05of those built-in formatting classes, like ljust, rjust, and center.
Collapse this transcript
Finding restaurants
00:00Now that we are able to add restaurants to the restaurant file and we are able
00:03to list back all the restaurants that are in the file, the last remaining action
00:07that we needed to code is the find action.
00:09So we want to be able to find based on certain keyword and we will only get back
00:14to results that match that keyword, which is instead just having a single
00:18command like add or list, we now have both find and the keyword that we want to find.
00:23That keyword is going to be an argument that's going to be passed into the
00:27find method so it can find what we are looking for.
00:29Let's see how to add that functionality.
00:32So here I am in guide.rb and in the do action, I've gone ahead and just added
00:36the find, for when find we are going to execute find and I have written a find
00:40method here and we are going to use the output action header that we just
00:43wrote in the last movie.
00:44That's all pretty standard stuff.
00:45What we need now is a way to pass in arguments here. Let's say keyword.
00:51It's going to be equal to and we will make it default to nothing.
00:55We want to be able to pass that keyword in.
00:57To do that it's going to get from the command line here where we get action.
01:01It's going to get passed all the way down the line until it gets to the find method.