IntroductionWelcome| 00:00 | (Music playing.)
| | 00:03 | Welcome to Ruby Essential Training.
| | 00:05 | My name is Kevin Skoglund.
| | 00:07 | I run a web development company called
Nova Fabrica, where we develop websites
| | 00:10 | and web applications.
| | 00:12 | In this course, we are going to
learn to program using Ruby, the popular
| | 00:15 | object-oriented programming language.
| | 00:18 | To begin with, we will examine the
basic object types in Ruby, as well as the
| | 00:21 | fundamentals of the language syntax.
| | 00:23 | We will learn how object-oriented
programming works and I'll walk you through
| | 00:26 | the steps to enable you to read
and to write to files from your code.
| | 00:30 | Finally, we'll get practical hands-
on experience using Ruby by building a
| | 00:34 | restaurant guide for
managing your favorite restaurants.
| | 00:37 | Now, it doesn't matter if you're
a beginner or if you have prior
| | 00:39 | experience. We'll cover all the fundamentals
you need and many more advanced concepts as well.
| | 00:44 | If you're interested in website
development, you will end with a solid
| | 00:47 | foundation in Ruby that will make
learning Ruby on Rails much easier.
| | 00:50 | Let's get started learning
how to program with Ruby.
| | Collapse this transcript |
| Using the exercise files| 00:00 | If you are a Premium member of the
Lynda.com Training Library, or if you're
| | 00:04 | watching this tutorial on a disc,
then you will have access to the exercise
| | 00:07 | files that accompany this title.
| | 00:09 | The exercise files are
arranged by chapter and by movie.
| | 00:13 | You can find the exercise files that
corresponded to the movie you're watching
| | 00:15 | by first looking for the chapter
number and then the movie number.
| | 00:18 | Now, of course to use the exercise
files, you want to make sure that you have
| | 00:21 | Ruby installed first, and
Cchapter 1 can help you with that.
| | 00:24 | Once you're confident you have
everything installed, then you will want to copy
| | 00:27 | the folder of Exercise Files to a
convenient location, like your Desktop.
| | 00:31 | It's a good idea to do it as a copy, so
that you still have the original files
| | 00:34 | to refer back to once you make changes.
| | 00:36 | On my Mac, I will Option+Drag the
folder to the Desktop in order make a copy.
| | 00:41 | Once it's copied, then we can just
remove the chapter number and movie number
| | 00:44 | from the front of the file name, and
now your files will be the same as mine,
| | 00:48 | and you'll be able to work right along with me.
| | 00:49 | Don't forget you can also use the
exercise files to check your work as you go along.
| | 00:53 | We've done something a little bit
different for Chapters 2, 3, and 4.
| | 00:57 | Instead of having a folder full of files,
there's just a single Ruby file, which
| | 01:01 | is actually a transcript of
what I type during the movie.
| | 01:05 | So this is there as a
convenience for you to refer to.
| | 01:07 | You can actually run it as a Ruby file
and get the same results, or you can just
| | 01:11 | refer to it, as I'm typing the same
thing during the course of the movie.
| | 01:15 | If you're a monthly or annual
subscriber to Lynda.com, you won't have the
| | 01:18 | exercise files that accompany this tutorial,
but you can follow right along with me.
| | 01:22 | Everything that's in the exercise files
we will create during the tutorials.
| | 01:26 | So as long as you continue to work along
with me, your files will exactly mirror
| | 01:30 | what's in the exercise files.
| | 01:31 | Remember 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 RubyIntroducing Ruby| 00:00 | I'd like to start out our Ruby
Essential Training by introducing Ruby to you,
| | 00:03 | and first answering the question, what is Ruby?
| | 00:06 | You probably already know that
Ruby is a programming language.
| | 00:08 | Its a language that was created in
Japan, in 1995, by Yukihiro Matsumoto.
| | 00:13 | People just call him Matz for short.
| | 00:15 | Ruby has a syntax or a language structure
that's a lot like Perl, Python, and Smalltalk.
| | 00:20 | In fact, Matsumoto said that when he
created Ruby, he was trying to create a
| | 00:23 | language that was more powerful than Perl,
and more object-oriented than Python.
| | 00:27 | Now, if you don't know any of those
other three languages, that's not a problem.
| | 00:31 | I'm going to teach you everything
about Ruby that you need to know.
| | 00:33 | But if you do already know them, you'll
have a little bit of a head start and
| | 00:36 | you'll recognize a lot of the
things in Ruby as we go through them.
| | 00:39 | Now, Ruby is not a compiled language.
| | 00:42 | Some other compiled languages
would be C++, Java, or Visual Basic.
| | 00:46 | A compiled language is a language where
you write the code and then you have to
| | 00:49 | run it through another computer program
or compiler in order to come out with an
| | 00:53 | application that you can
actually run at the end.
| | 00:55 | Well instead, Ruby is going
to be an interpreted language.
| | 00:58 | So we're going to write our code and
then it will just get interpreted straight
| | 01:02 | from the code when we're ready to run it.
| | 01:04 | So we're not going to have to go
through this extra step of compiling it into
| | 01:08 | something that will run.
Our code will run on its own.
| | 01:10 | But we're going to need to have
a Ruby interpreter to do that.
| | 01:14 | So in the Installation section we will
be installing the Ruby interpreter that
| | 01:18 | will let us do that.
| | 01:18 | Now, you may be coming to this
training because you've heard positive things
| | 01:21 | about Ruby, but you may not really be sure
why Ruby, why not one of these other languages?
| | 01:26 | Well, first and foremost, Ruby is
fully object-oriented, and if you're not
| | 01:30 | familiar with object-oriented, we'll
talk about it a lot more later on and
| | 01:33 | you'll see why it's such a good thing.
| | 01:34 | If you're are familiar with it from
other languages, you'll find that Ruby is
| | 01:38 | very object-oriented. Almost
everything in Ruby is an object.
| | 01:41 | That's a really nice way to work,
once you're used to working with objects.
| | 01:44 | Ruby also has easily readable code.
| | 01:46 | It reads a lot like English.
| | 01:48 | So we don't spend a lot of time
trying to decipher the code that's on the
| | 01:51 | screen to understand what our program is doing.
| | 01:54 | When we're writing our code, it also
has an unsurprising syntax, naming,
| | 01:58 | and behavior to it.
| | 02:00 | So things often just work the
way you'd expect them to work.
| | 02:03 | If you say you want to sort, then it sorts it.
| | 02:05 | If you want to find, it finds.
| | 02:07 | Reverse, reverses, and so on.
| | 02:09 | Another nice feature that's common
to a lot of languages now is that it's
| | 02:12 | whitespace independent.
| | 02:14 | So having extra tabs or extra
spaces doesn't really make a difference.
| | 02:18 | And unlike a lot of
languages, there are no semicolons.
| | 02:21 | If you've worked with semicolons in
another language, like PHP, for example,
| | 02:24 | you're going to love the fact that you
don't have to worry about that trailing
| | 02:28 | semicolon at the end.
Ruby can sort it out for you.
| | 02:31 | Last of all, Ruby has lots of
what we call syntactic sugar.
| | 02:35 | That means that the syntax of the
language is such that it helps you out.
| | 02:39 | It does nice things for you, or allows
you to write things in a simpler way so
| | 02:43 | that we can have sort of a
shortcut for ourselves. That's the sugar.
| | 02:46 | The opposite of syntactic
sugar is syntactic vinegar.
| | 02:49 | So it's a pleasant way of
working with the syntax.
| | 02:51 | And there are lots of nice bits of
syntactic sugar in Ruby and we'll see those
| | 02:54 | as we learn the basics.
| | 02:55 | I also just want to take a second to
clear up a common misconception and that
| | 02:59 | is the difference
between Ruby and Ruby on Rails.
| | 03:02 | Ruby on Rails has gotten a lot of
publicity, because a lot of people are using
| | 03:05 | it for their web development.
| | 03:07 | I use it and I love it.
| | 03:08 | But what we're talking about here is Ruby,
and that's different from Ruby on Rails.
| | 03:11 | Ruby on Rails is a web
framework that's been written in Ruby.
| | 03:16 | So it uses Ruby to build a web framework.
| | 03:18 | So when we're talking about Ruby on Rails,
we're talking about the web framework
| | 03:22 | that helps you build websites.
| | 03:23 | When we talk about Ruby though,
we're just talking about the language and
| | 03:27 | it's a multipurpose language.
| | 03:28 | It's not just for the web.
| | 03:30 | In fact, in our exercises in this
tutorial we're going to create a standalone,
| | 03:34 | non-Internet application,
that won't use the web at all.
| | 03:37 | So you'll be able to see how Ruby
can be used outside of the web context.
| | 03:41 | Now that we've taken a look at what
Ruby is, we're ready to make sure that we
| | 03:44 | have that Ruby interpreter
installed on our computers.
| | Collapse this transcript |
| Installing Ruby on a Mac| 00:00 | In this movie, I am going to help Mac
users get everything installed that they
| | 00:03 | need to be able to program in the Ruby language.
| | 00:05 | I am going to start by first giving
an overview and then I'll walk you
| | 00:08 | through it step-by-step.
| | 00:09 | The first thing I want to do is point
you to the primary resource for the Ruby
| | 00:12 | language and that's the Ruby
language website, ruby-lang.org.
| | 00:17 | So if you go to that website, it will
always have the latest information about
| | 00:20 | the current version of Ruby and even
some installation instructions and some
| | 00:24 | links to download it.
| | 00:25 | So if the things that I tell you about
installation change in the future,
| | 00:29 | let's say a new operating system version
comes out or suddenly some kind of bug comes up,
| | 00:33 | so that it's not working anymore,
your first resource that you want to go to
| | 00:36 | is that ruby-lang site and see if
you can find the problem there, because
| | 00:40 | they'll probably let you know, "look,
this is what you need to do if you're using
| | 00:43 | this operating system" and so on.
| | 00:45 | We'll take a look at that in a moment.
| | 00:46 | The first of the pieces that we know
we're going to need to be able to program
| | 00:49 | in the Ruby language is the Ruby interpreter.
| | 00:52 | It's going to interpret Ruby for us.
| | 00:54 | If you're using Mac OS X, you
probably already have a version of
| | 00:56 | Ruby pre-installed.
| | 00:57 | Now this may not be the correct version and
you may need to update it. Let's take a look.
| | 01:01 | So if you have 10.1, you may
have problems running Ruby.
| | 01:05 | Some people have had success, some
people have had trouble. Hopefully,
| | 01:07 | that's an operating system that's now seven or eight-
years-old and you've upgraded to something else.
| | 01:12 | 10.2 and 10.3, you'll want to either
install or upgrade Ruby by following the
| | 01:16 | instructions on that Ruby language site.
| | 01:19 | And if you're on 10.4, which is Tiger,
or 10.5, Leopard, which is where I am
| | 01:23 | guessing most of you are, you'll have
a version of Ruby that's going to work
| | 01:27 | perfectly fine for the purposes of our tutorial.
| | 01:30 | You could go ahead and
upgrade to a newer version.
| | 01:33 | In fact, there is a newer version than
1.8.6 out and there may be other ones
| | 01:36 | after this training is published, they come out.
| | 01:38 | You can go ahead and use those newer
ones if you want, but you'll want to make
| | 01:41 | sure that you have something at least
1.8.2 before proceeding and that's what
| | 01:45 | ships with those and no
installation will be needed.
| | 01:48 | So you'll be all set to go.
That makes it nice and easy for you.
| | 01:51 | The other two pieces that we're going to
need are the text editor and the command line.
| | 01:54 | The text editor is going to
let us write files in Ruby code.
| | 01:58 | The command line is going to let us run
those files and also interact with our
| | 02:02 | Ruby interpreter in an interactive way.
We'll see how to do that.
| | 02:05 | Any text editor will really work.
| | 02:07 | You don't want to use something like
Microsoft Word or something; you want to
| | 02:09 | use just a plain text editor that
doesn't insert lots of formatting, or
| | 02:13 | anything like that, just plain text,
and the best ones are ones that are going
| | 02:16 | to do code coloring for you.
| | 02:18 | That is they're going to give color
to the syntax on the page, so that you
| | 02:21 | can quickly look at your code and tell what's
what because things are of different colors.
| | 02:25 | It's a nice feature that most text editors have.
| | 02:28 | The text editor that I
always recommend is TextMate.
| | 02:31 | I think it's a fantastic one and I
think you can't go wrong with it.
| | 02:34 | macromates.com is the company that makes it.
| | 02:36 | You can just go to their website.
| | 02:38 | It's not that expensive to buy, but you
also can download a free trial, if you
| | 02:41 | want to try it out and it does code
coloring and there is lots of other nice
| | 02:45 | features that I think you'll
really come to appreciate over time.
| | 02:47 | So do yourself a favor and check that out.
| | 02:50 | And for the command line, we'll be
using Apple's program called Terminal
| | 02:53 | and that is inside the Applications
folder, inside Utilities, you'll find
| | 02:56 | the program called Terminal. We can
run that to directly interact on the
| | 03:00 | command line with the Unix
operating system that's running Mac OS X.
| | 03:04 | So let's take a look now.
| | 03:06 | Here I am on the Ruby Language website.
| | 03:08 | You'll notice that there is a download
link here and there is also one here.
| | 03:11 | Those take me to the same place
and that lets me download Ruby.
| | 03:15 | You'll see that it gives me the Ruby Source
Code if I want to download the full source.
| | 03:19 | Ruby 1.9, it actually offers to give me
in that format, or I can scroll on down
| | 03:25 | past Windows and Linux, until I get to
Ruby On OS X and it basically tells you
| | 03:29 | the same information that I just told you,
and gives you some more helpful links
| | 03:33 | if you want to upgrade and I wanted to
point out down here, probably the best
| | 03:37 | things of all for Tiger and Leopard,
these articles down here will take you to
| | 03:42 | the steps of installing Ruby and also Rails.
| | 03:45 | Now we only want to follow the first
couple of steps to get Ruby installed.
| | 03:48 | It goes on and installs MySQL
and Rails and everything else.
| | 03:51 | We're just going to want to focus on
Ruby but those can all be helpful for you,
| | 03:54 | if you decide that you want to upgrade.
| | 03:56 | Now let's take a look at our command line.
| | 03:57 | If I go to Applications to my
Applications folder, if I go into Utilities, inside
| | 04:04 | my Utilities, if I scroll down, you'll
see I have Terminal and this will open
| | 04:08 | up our command line that will allow us to
interact directly with the Unix operating system.
| | 04:11 | Now I want to start out by just saying ruby
and then dash v and that should work for you.
| | 04:17 | If you have Ruby installed,
it should come up and tell you which version,
| | 04:21 | just by typing ruby -v.
| | 04:22 | If you didn't get that, then you
don't have Ruby installed or else there is
| | 04:26 | something that's gone wrong and
you'll need to troubleshoot it.
| | 04:29 | But on Tiger and Leopard, you should
get back either Ruby 1.8.2 or something
| | 04:34 | later than that by just issuing that command.
| | 04:36 | We can also type in which ruby and it
will actually tells us where it's located
| | 04:41 | and that's also useful to know.
| | 04:42 | It's inside usr/bin and that's
where the program has actually been put.
| | 04:46 | It's inside that folder.
| | 04:47 | So that's the version of Ruby that we
are running and that's where it's located.
| | 04:50 | So we know that we have Ruby.
We know that we now have a command line.
| | 04:53 | The last thing is just go to that
MacroMates website that I told you about,
| | 04:57 | macromates.com.
| | 04:59 | Here it is for TextMate.
| | 05:00 | You'll see we have a free 30-day trial.
| | 05:02 | You can just download.
| | 05:03 | It's a simple installer; you can
go ahead and do that for yourself.
| | 05:06 | I've already installed it and once I
downloaded it and installed it, then I just
| | 05:10 | simply drag a copy of it to my dock here,
so that I have it nice and accessible.
| | 05:14 | I have also got Terminal that I've
just dragged to my dock so that that's
| | 05:16 | accessible as well, and I can just
switch between those to bring them up.
| | 05:20 | That's all we need to be able
to use Ruby. It's that easy.
| | 05:23 | Luckily, all this is a pre-installed with the
Mac, so there is really just not that much to do.
| | 05:27 | Now, we are ready to start using Ruby.
| | Collapse this transcript |
| Installing Ruby on Windows| 00:00 | In this movie I am going to help
Windows users get everything installed that
| | 00:03 | they are going to need to be able
to program in the Ruby Language.
| | 00:06 | Let me start by first giving you an
overview of the installation and then
| | 00:09 | I will walk you through it step by step.
| | 00:10 | The first thing I want to show you is
the main resource for the Ruby Language,
| | 00:13 | and that's the Ruby Language
website, and that's www.ruby-lang.org.
| | 00:19 | You can always go to this website in
order to get the latest information about
| | 00:22 | Ruby and to get help with installing.
| | 00:24 | So if any of the installation
instructions that I give you coming up in this
| | 00:27 | movie fall out of date, let's say a
newer operating system comes out or some
| | 00:31 | kind of incompatibility with a
future version of Ruby comes up, this is the
| | 00:35 | first place you will want to go to
troubleshoot it, because they will help you
| | 00:37 | figure out what version you ought to be
installing with what operating system.
| | 00:39 | Now let's walk through
what we need for installation.
| | 00:42 | There are going to be three pieces.
| | 00:44 | The first is the Ruby interpreter.
| | 00:46 | Remember we talked about that Ruby is
an interpreted language, so we will need
| | 00:48 | to install that interpreter.
| | 00:49 | It doesn't come with Windows by default.
| | 00:52 | The easiest way to do that is going
to be a one-click installer that's on
| | 00:55 | that ruby-lang site.
| | 00:56 | At the moment if we use that one-click
installer, it's going to install Ruby
| | 00:59 | version v1.8.6 for us.
| | 01:01 | Now, there are newer versions of
Ruby that are already available.
| | 01:04 | In fact, we are all the way up to 1.9 now.
| | 01:06 | And that one-click installer may be updated
in the future to have a different version.
| | 01:10 | Don't worry about which version it is.
| | 01:11 | Any version is going to work for the
things that we are going to do in this tutorial.
| | 01:14 | So go ahead and install whatever
version is in that one-click installer and you
| | 01:18 | should be good to go.
| | 01:19 | The second thing we will want to make sure
we have available to us is a text editor.
| | 01:23 | Any plain text editor will work for us.
| | 01:25 | What you won't want to do is use
something like a word processing program, like
| | 01:28 | Microsoft Word, that includes a lot of
formatting information in addition to the text.
| | 01:33 | We want just the text, so that the
formatting information doesn't get in the way.
| | 01:36 | Now, the best text editors are going
to be ones that offer us code coloring.
| | 01:40 | That is that they are going to give
our syntax, our Ruby Language, different
| | 01:44 | colors to different parts of the language.
| | 01:46 | So that makes it nice and easy for us
to see what's happening on the page,
| | 01:49 | because things are broken up by color.
| | 01:51 | There are lot of text editors out there.
| | 01:52 | I am just going to mention two.
| | 01:53 | The first is SciTE, which
comes with the Ruby installer.
| | 01:56 | So when we use that one-click installer, we
will also get SciTE and we could use that.
| | 02:00 | A third party one that I
would recommend is E Text Editor.
| | 02:03 | Its the sister program to the
MacroMates' TextMate program, which is on the Mac.
| | 02:08 | It works just the same way.
| | 02:09 | It's a great text editor.
| | 02:11 | It offers code coloring and everything.
| | 02:13 | I believe it's not very expensive to
purchase it, but they also have a trial period,
| | 02:16 | if you want to just
download it and try it.
| | 02:18 | The third piece that we are going to need
is going to be a command line interface.
| | 02:21 | That's going to allow us to actually
interact with Ruby and run our Ruby programs.
| | 02:25 | That comes with Windows.
| | 02:27 | It's inside the Accessories
folder and it's called Command Prompt.
| | 02:30 | So we already have that installed and
I will show you where that's located.
| | 02:33 | Now let me walk you through the steps.
| | 02:35 | Here I am on the Ruby Language website,
and you will see there is a link here
| | 02:38 | for Downloads and there is another
one over here that says Download Ruby.
| | 02:41 | Those take me to the same page.
| | 02:43 | So that will take me over
here to the Installation page.
| | 02:45 | You will see it says the current
stable version at the moment is 1.9.1.
| | 02:48 | Now, it may change by the time you
watch this video, but don't worry about it.
| | 02:52 | What we are interested in is going down
here to the Ruby on Windows section, and
| | 02:56 | the one-click installer.
| | 02:58 | So whatever the one-click installer is here
with the latest version is what you want to use.
| | 03:01 | 1.8.6 is what it is at the moment.
| | 03:04 | So we will click that.
| | 03:05 | Windows of course will pop-up and say,
what do you want to do with this?
| | 03:08 | I will say let's run it.
| | 03:09 | It will just take a moment while it downloads.
| | 03:11 | Once your file is downloaded, if
Microsoft Windows gives you a security warning,
| | 03:15 | you will want to say Yes,
it's okay to run this program.
| | 03:17 | We will go ahead and allow the program to run.
| | 03:20 | Now it's hidden, but it's down
here in my bar, and there it is.
| | 03:23 | The Wizard has popped up for
installing Ruby 1.8.6. I will click Next.
| | 03:27 | I will Agree to the terms
of the License Agreements.
| | 03:29 | You will see it's going to
install SciTE at the same time.
| | 03:32 | We also have RubyGems and
European Keyboard that we can install.
| | 03:35 | If you know that you are going to want
to use Ruby on Rails at some point,
| | 03:39 | you would want to go ahead
and enable RubyGems as well.
| | 03:42 | I am going to leave it off for now.
| | 03:44 | Then it's going to install Ruby you can see.
| | 03:45 | So I will hit Next.
| | 03:47 | The Destination, go ahead and take
whatever it gives you as a default and
| | 03:52 | we will say Install.
| | 03:55 | And then just sit back
and wait while it installs.
| | 03:57 | Once your installation is
complete, you will want to click Next.
| | 04:01 | And then click Finish.
| | 04:02 | Now our installation is complete.
| | 04:05 | We can close up Internet Explorer and
then we can go to All Programs from the
| | 04:10 | Start menu and what we want to look
for here is Accessories and inside
| | 04:14 | Accessories you will find Command Prompt.
| | 04:17 | You could also do a search for
Command Prompt and this will then take you
| | 04:20 | to the Command Prompt.
| | 04:21 | So now we know where that's located.
| | 04:22 | We know how to find that.
| | 04:24 | We should be able to just type ruby-v,
and it comes up and tells us, yes,
| | 04:28 | you have Ruby installed
and it's version 1.8.6.
| | 04:32 | If we had tried that before the
installation, ruby-v, it would have just told us
| | 04:36 | that, sorry, I don't understand that command.
| | 04:38 | I don't have Ruby installed.
| | 04:40 | You remember that the last piece we
need is going to be the text editor.
| | 04:42 | So you can download E Text Editor.
| | 04:44 | That's what I have already done here,
or I just want to show you where
| | 04:47 | that SciTE program is.
| | 04:48 | If you go to All Programs and then
inside the Ruby folder, where it installed
| | 04:52 | everything, you will find
SciTE right here, SciTE.
| | 04:56 | So click on that and now we are inside
that SciTE text editor, so that you can
| | 05:00 | go ahead and start typing here, for example.
| | 05:02 | We will talk about what to
type and how to get that going.
| | 05:05 | But that's where that application
is loaded, if it installed with it.
| | 05:08 | So you have a text editor, but you
can also download another one or use
| | 05:12 | something else if you are
more comfortable with it.
| | 05:13 | That's all there is to getting
things installed with Windows.
| | 05:16 | Now we are ready to start using Ruby.
| | Collapse this transcript |
| Using Ruby| 00:00 | Now that we have everything we need
for programming in Ruby installed on our
| | 00:03 | computers, we are ready to
take a look at how to use Ruby.
| | 00:06 | There are three different
ways that I want us to look at.
| | 00:09 | The first is going to be a single command.
| | 00:11 | The second will be using a Ruby file,
actually saving a file that has Ruby code in it.
| | 00:16 | The third will be IRB,
the Interactive Ruby Shell.
| | 00:20 | Now, we are going to look at the first
two in this movie and we will spend some
| | 00:22 | more time with IRB in the next movie.
| | 00:25 | All three of these ways of interacting
with Ruby are going to require that we
| | 00:28 | use our command line.
| | 00:29 | So here I am inside my command line
program on the Mac, which is Terminal.
| | 00:32 | If you are on a PC, you will want to
use the Command Prompt application that we
| | 00:36 | talked about in the Installation section.
| | 00:38 | But once you come up in there, you
should be able to type Ruby and then -v,
| | 00:41 | and it will let you know that you have Ruby
installed and report what version you have.
| | 00:45 | Again, don't worry if your version is
not the same as mine. We talked about in
| | 00:48 | the Installation section that most
versions are going to work just fine, as long
| | 00:51 | as we have Ruby installed.
| | 00:53 | Running a single command is as easy as
typing Ruby and then -e, to let it know
| | 00:58 | they we are going to use a
single command version of Ruby, -e.
| | 01:02 | And then a single quote and our Ruby
command, puts 123, and another single quote.
| | 01:08 | That's the command that we
want to execute, the single line of Ruby.
| | 01:12 | So now we have learned our first Ruby
command, puts, and that's actually 123,
| | 01:17 | not 1, 2, 3, even though I said it 1, 2, 3.
| | 01:19 | We will hit Return, and you will see
what it does. puts actually output 123.
| | 01:25 | It put it to whatever our standard
out was, which in this case was just
| | 01:29 | the Terminal window.
| | 01:30 | Before we move on, let's go ahead and
take a look at our second Ruby command,
| | 01:33 | which is going to be print.
| | 01:36 | It does something very similar to puts.
| | 01:38 | Now, notice the difference. Notice
where print went. print is right before my
| | 01:42 | command prompt. The difference is
that there is no line return after print.
| | 01:46 | So puts outputs whatever you asked it
to and adds a line return at the end.
| | 01:51 | print just outputs whatever you have asked
it to do, and does not put that line return.
| | 01:55 | So now we know two bits of Ruby, puts and print.
| | 01:57 | Let's take a look at how
to do this with the file.
| | 02:00 | In order to do that, we
will need our text editor.
| | 02:01 | I am going to open up TextMate, which
is mine, and I am just going to put a
| | 02:04 | simple Ruby command in here, puts 123,
and then right after it let's put print
| | 02:09 | 456 and then puts 789.
| | 02:12 | So we are going to Save this and we are
going to call this file simple_file, and
| | 02:18 | the ending is going to be .rb, to let
it know that it's a Ruby file that ought
| | 02:22 | to be run with Ruby. .rb is
going to be the extension.
| | 02:24 | We are always going to want to use that.
| | 02:27 | You can save it anywhere you like.
| | 02:28 | This is not like a web application where
we need to put these in a certain sites
| | 02:31 | directory or something like that.
| | 02:32 | These can be run absolutely anywhere
on your computer, but you want to put it
| | 02:36 | someplace that's easy for you to find.
| | 02:38 | I am going to go ahead and
just put it on my Desktop.
| | 02:40 | You can put it anywhere,
in your Documents folder.
| | 02:42 | It doesn't really matter, as long as you
are able to find it from the command line.
| | 02:45 | So I am going to save it
there. So now it's saved.
| | 02:48 | You see the code coloring took effect.
That's the code coloring inside TextMate.
| | 02:52 | Yours may be different, that's fine.
| | 02:54 | If I come back over here to the
command line now, I will need to navigate
| | 02:57 | to where that file is.
| | 02:59 | So we can see a list of the files that
are in the current directory using ls, if
| | 03:03 | we are on a Mac, or dir, if you are
on a PC, and that will tell you what's
| | 03:08 | inside that directory.
| | 03:09 | We can change directories
by using the cd command.
| | 03:12 | So I am going to do cd into my Desktop folder.
| | 03:15 | Hitting Tab allowed me to auto complete
that name and then when I switch to the
| | 03:19 | Desktop, now if I do an ls, you will
see that I see that simple_file there.
| | 03:23 | So once we are in the same directory as
the file, then we can simply run Ruby,
| | 03:29 | and then the filename, and once again
the Tab lets me auto complete that name.
| | 03:32 | So ruby simple_file, let's run it, and
look what it output, 123, and then 456789.
| | 03:39 | Now, notice if we go back, either we
used puts here, print here, and puts here,
| | 03:45 | and you will see the effect of not having
that line return between the 6 and the 7.
| | 03:48 | So that's all there is to
being able to run a Ruby file.
| | 03:51 | Now, if we hadn't navigated into Desktop,
we could still do it just by providing
| | 03:55 | the full path to the file.
| | 03:57 | So if I go backwards a directory, we
do that with the ..cd, and then dot dot
| | 04:01 | goes back one, into the parent
directory, and now I could just as easily say
| | 04:05 | Ruby, and then Desktop/simple_file.rb,
and that will also run that same file.
| | 04:12 | So we just need to either be in the
same folder, or we need to specify the full
| | 04:15 | path on how we can get there.
| | 04:17 | Before we move on, I just want to
point out a couple of things about the file
| | 04:19 | that we are working with here.
| | 04:20 | First of all is that Ruby
is whitespace independent.
| | 04:24 | So it doesn't matter whether you put
some extra whitespaces here, some extra
| | 04:27 | ones here, it's still going to sort that out.
| | 04:31 | So it's not going to
really matter where those are.
| | 04:32 | If we save this, come back here and we run
the file again, you see we get the same results.
| | 04:38 | The second thing I want to point
out to you is the way we do comments.
| | 04:42 | A comment in Ruby is simply the pound sign,
also sometimes called the hash or the sharp.
| | 04:47 | So we will put that in
front of any of our comments.
| | 04:49 | So then I will say print does not add a
line return, and now we have a comment.
| | 04:56 | Something that we can comment in
our code and will not get executed.
| | 04:59 | Notice also that we are not using any
kind of semicolons or anything like that
| | 05:02 | at the end of our lines.
| | 05:03 | We just simply have a simple line return,
and Ruby then knows, hey, we are ready
| | 05:07 | to move on to something else.
| | 05:09 | Print got everything that it needed
on this line, so it's not waiting for
| | 05:12 | more data to come in.
| | 05:13 | So that must mean this is a new
command, starting on the next line.
| | 05:16 | So let's save it, and let's just run it to
reassure ourselves that it all still works.
| | 05:20 | Now, running a single command in Ruby
isn't going to be useful for us that often.
| | 05:24 | Running a file is going to be very
useful for us, especially if we have lots and
| | 05:28 | lots of code. We are not going to want
to retype it every time. We will want to
| | 05:31 | put it in a file, save it, and run it.
| | 05:33 | But there is also Interactive Ruby Shell,
which is going to be very useful for us,
| | 05:38 | especially at the
beginning, to try things out quickly.
| | 05:41 | Once we actually start writing a
program, we will put it in a file.
| | 05:43 | For now, let's move over and look at IRB.
| | Collapse this transcript |
| Interactive Ruby Shell (IRB)| 00:00 | Now that we have seen the first two
ways that we can interact with Ruby,
| | 00:02 | either using a single Ruby command,
or creating a file with all of our Ruby code in it,
| | 00:06 | now let's take a deeper look at the
Interactive Ruby Shell, or more simply called IRB.
| | 00:12 | IRB is going to be a
command line interface to Ruby.
| | 00:15 | Now, why that's really great is because it
allows us to really interact with our code.
| | 00:19 | We can see what's happening in real-time.
| | 00:21 | It's a lot like a calculator.
| | 00:23 | We can type in a couple of values, get
a result, type in a few more values, get
| | 00:27 | a different result, and then we can
compare and see how things are working.
| | 00:30 | It's a great place to test our code.
| | 00:32 | So even when we are really advanced and
we are writing all of our code in a very
| | 00:36 | complex system of files that are all
connected together, IRB is going to be a
| | 00:41 | great way to quickly just pop open Ruby,
try something out, test our theory, and
| | 00:45 | then go back and actually add it to our code.
| | 00:47 | So let's take a look.
| | 00:49 | The way that we will access IRB is
going to be from the command line.
| | 00:52 | So when I say command line on a Mac, I
am talking about the Terminal application
| | 00:55 | that's inside your Utilities folder,
and on a PC, that will be the Command
| | 00:58 | Prompt application that's
inside your Accessories folder.
| | 01:01 | We saw how to find those earlier.
| | 01:03 | To run it, we simply type
irb at the command line.
| | 01:06 | IRB is a program that's
installed when we install Ruby.
| | 01:09 | So we have irb, now I am inside, and
you see I have a prompt there, letting me
| | 01:13 | know that I am in IRB,
it's waiting for a command.
| | 01:16 | Now, IRB works a lot like a
calculator. We can do 1+1.
| | 01:21 | Comes back and tells us that it's 2.
| | 01:23 | Or we can say 4+5, 9.
| | 01:26 | Let's try something a little more
complex, 3 * 50, or let's try 45/9.
| | 01:34 | And last of all, let's just
do some subtraction, 100-10.
| | 01:36 | So you see that it just works like a
calculator and just returns these values to us.
| | 01:42 | Now, let's try the
commands that we used earlier.
| | 01:44 | We used puts, if you remember, 123.
| | 01:47 | Now, this brings up an important
point about IRB that I want you to pay
| | 01:50 | close attention to.
| | 01:51 | Notice that it returned two things to me.
| | 01:54 | The first thing is 123, and then
the arrow notation is next to nil.
| | 01:59 | Just like we had the arrow
notation up here, next to 90.
| | 02:01 | So what's going on here?
| | 02:03 | Puts is outputting it to IRB, just
the same way that it outputted to our
| | 02:08 | command line before, when we were running it
from either the file or from a single line.
| | 02:12 | This is the return value that comes back.
| | 02:15 | So this is both the output that's
happening and there is the return value and
| | 02:19 | the return value of puts is always nil.
| | 02:22 | The return value of these calculator
operations that we were doing up here is
| | 02:26 | the value that we are looking for.
| | 02:28 | It's not actually outputting it;
instead it's doing the calculation and
| | 02:32 | giving us a return value.
| | 02:34 | So this is an important difference.
| | 02:35 | Let's try this, puts 1+1,
and notice what it gives us.
| | 02:39 | See, we get the 2 that's being put,
and the return value is nil and that's
| | 02:45 | distinctly different from just doing 1+1.
| | 02:48 | So keep this in mind, because when we
are doing a puts, which we will be doing a lot,
| | 02:51 | we are going to be outputting something
to the command line, so that we can see it,
| | 02:55 | but the return value may be simply nil.
| | 02:59 | Now, it's worth mentioning that
nil means nothing. It's not 0.
| | 03:02 | It's actually less than 0. It's nothing.
| | 03:04 | It doesn't exist.
It's no value at all.
| | 03:07 | In a lot of languages this
is just referred to as null.
| | 03:09 | In Ruby it's going to be nil all the time.
| | 03:13 | The next thing I want to point out to
you about IRB is that you should be able
| | 03:16 | to use your up arrows to get to old
commands that you have issued before, and
| | 03:19 | you can just hit return to
execute them again, or the down arrow.
| | 03:23 | Once you go up a few, you can
come back down a few the same way.
| | 03:25 | That can be really handy for finding an
old command that you typed, especially
| | 03:28 | if it's a long line, and just
allowing it to be reentered another time.
| | 03:33 | The other thing I want to
introduce is a bit of the Ruby syntax.
| | 03:35 | I am going to put a double quote, followed by
Hello, and then a dot, and the word reverse.
| | 03:41 | So now we are actually writing some Ruby code.
| | 03:43 | We will talk a little bit
more about what Hello is later.
| | 03:46 | For now just know that it's an object.
| | 03:48 | We have told that object to reverse
itself, and this is the thing I want you to
| | 03:52 | notice is the dot notation here, and
the dot notation tells it to reverse.
| | 03:57 | Then in order to get out of IRB, we
simply type quit, and that takes us back
| | 04:01 | to our command prompt.
| | 04:02 | Now, there is one other thing I want
to show you about IRB, which is if we do
| | 04:05 | IRB and then --simple-prompt, there
we go, --simple-prompt, then we get a
| | 04:13 | simpler prompt, 1+1.
| | 04:16 | Everything works exactly the same;
we just have a much shorter prompt line at
| | 04:20 | the end of each one.
| | 04:21 | Some people like the longer one.
| | 04:22 | It gives you line numbers and
everything. The other one doesn't.
| | 04:25 | It just sort of gets all that out
of your way. So it's up to you.
| | 04:28 | You may already be
configured to use the simple prompt.
| | 04:30 | If so, that's fine.
| | 04:31 | But this will allow us to have either
the simple prompt or the complex prompt,
| | 04:35 | depending on your preference.
| | 04:36 | I will type quit one last time, and
that's all you need to know to get
| | 04:39 | started working with IRB.
| | Collapse this transcript |
| Documentation| 00:00 | Before we dive into learning Ruby,
there is one last thing that I wanted to
| | 00:03 | introduce in this Getting Started
section, which is the documentation on Ruby.
| | 00:07 | The best place to get the documentation
is from the Ruby Documentation website,
| | 00:11 | and that's www.ruby-doc.org/core/. Now, if
you were just to go to the ruby-doc website,
| | 00:19 | you will be able to find the core
API for your version of Ruby directly
| | 00:22 | from there, but core will
take you straight there.
| | 00:24 | So here I am on the ruby-doc website.
The link that I was talking about is the
| | 00:28 | 1.8.6 core. You will see that that's
going to take us to the same place that we
| | 00:31 | would have gone otherwise.
| | 00:32 | So that's just going to
be here, ruby-doc.org/core.
| | 00:36 | This is going to be all of the
different classes and methods and files that are
| | 00:40 | available to us in Ruby, and we can
do a search to find the things we want.
| | 00:43 | This will all make a lot more sense to
you as we start learning Ruby, but I want
| | 00:46 | you to know where it is now.
| | 00:48 | So for example, if I pick the class
string, you will see that it takes me to a
| | 00:51 | page about the strings and then I can
pick a method like upcase here, from its
| | 00:56 | methods, and we can see what it does,
and it reports back that string upcase
| | 01:00 | returns a copy of the string with all
lowercase letters replaced with their
| | 01:03 | uppercase counterparts, and
then it gives me an example.
| | 01:06 | So that's going to be the kind of
information we can get to find out how to use
| | 01:09 | these different methods inside
the different classes of Ruby.
| | 01:12 | Now, that same documentation is also
available to you from the command line.
| | 01:16 | So if we go into our terminal, we
can type ri, which stands for Ruby
| | 01:20 | Information, and then we can
type in something like upcase.
| | 01:24 | It will come back and it will report
to us about upcase, and it will say ah,
| | 01:27 | actually I have several different
things called upcase, which one do you mean?
| | 01:31 | You will notice here that it has String,
then the pound sign, and upcase, and
| | 01:35 | that's the format that it wants.
| | 01:37 | When you see END, you will want
to hit the Q to get back out of it.
| | 01:41 | So let's try it again with String#upcase,
and you will see that it comes back
| | 01:47 | and it says the exact same
information that we had on the website.
| | 01:50 | The difference is this is
stored locally on our computer.
| | 01:53 | So if, for example, we are on an
airplane and we are trying to remember how
| | 01:56 | something works, we can just pull it
up off of our laptop directly without
| | 02:01 | having to have an Internet connection.
| | 02:02 | So I will hit Q one last time.
| | 02:04 | Let's take a look at another one,
which is going to be ri Object#inspect.
| | 02:11 | Now, I just wanted to
introduce this idea of inspect to you.
| | 02:13 | Remember, almost everything is going to
be an object in Ruby, so this is going
| | 02:16 | to apply to a lot of different
things, and we can use inspect.
| | 02:20 | It's going to return a string containing a
human readable representation of the object.
| | 02:24 | So just keep that in mind. We will be
using inspect from time to time to just
| | 02:28 | see what an object looks
like in its human readable form.
| | 02:32 | Now, a lot of times it's hard to
represent a complex data structure as something
| | 02:36 | human readable, but it will do its best.
| | 02:38 | But I just wanted to introduce that
other bit of Ruby before we go on.
| | 02:41 | But the main thing to remember is that
for the documentation, you can go to the
| | 02:44 | ruby-doc website, or you can type in
ri for Ruby Information to get that same
| | 02:48 | information directly off of your computer.
| | 02:50 | It's stored with your Ruby installation.
| | 02:52 | Now that we have got everything
installed and we are oriented a little bit to
| | 02:55 | the way that the Ruby programming
language is going to work, we are ready to
| | 02:58 | actually start learning
the syntax of the language.
| | 03:01 | We will do that in the next chapter.
| | Collapse this transcript |
|
|
2. Ruby Object TypesObjects| 00:00 | In the introduction we discussed the
fact that Ruby is an object-oriented
| | 00:03 | programming language, and I have
pointed out several times that almost
| | 00:06 | everything in Ruby is an object,
and that's one of its strengths.
| | 00:10 | Now, in other languages
that's not always the case.
| | 00:12 | A lot of languages have something they
call primitives, which are like the basic
| | 00:15 | object types that we are about to talk
about, but primitives don't have a common
| | 00:19 | relationship to each other.
| | 00:20 | In the case of Ruby, all of these
object types that we are going to discuss are
| | 00:25 | all related because all of them are objects.
| | 00:27 | That's the fundamental building block
that everything else is built off of.
| | 00:31 | So keep that in mind in Ruby;
everything is an object.
| | 00:33 | Everything you manipulate is an object
and everything that's returned by your
| | 00:37 | manipulation is also an object.
| | 00:39 | So what is an object?
| | 00:40 | Well, we call it an object because it's
rather analogous to an object that you
| | 00:44 | would have in the real world.
| | 00:46 | So for example, in the real world we
would have an object that would be a
| | 00:49 | classroom, that's a thing, and that could be
modeled in Ruby as being an object as well.
| | 00:54 | In the real world we would have
students that would be in the classroom, and
| | 00:57 | those students would also be modeled
as objects, and each of the desk in the
| | 01:01 | classrooms could be an object and so on.
| | 01:02 | Now, in the real world, a classroom
can contain many desks and have many
| | 01:06 | students, who are sitting in a certain
order, and we can move students around
| | 01:10 | between the desks, have certain
students who are maybe absent on a certain day.
| | 01:13 | All those kind of complex
behaviors we can use objects to talk about.
| | 01:17 | It's really analogous to what we are used to
in the real world, which makes it nice and easy.
| | 01:21 | But objects can also be abstract.
| | 01:24 | We could have an object for the
communication that occurs between students.
| | 01:27 | We could treat their
conversation as if it was a physical thing.
| | 01:30 | So it's not always just going to be
an actual physical object that we are
| | 01:34 | thinking of when we are modeling things in Ruby.
| | 01:36 | Now, in programming terms an object
is actually an instance of a class.
| | 01:40 | We will talk a lot more about
instances and classes in Ruby a little later.
| | 01:44 | But using our example, each unique
student would be one example of the more
| | 01:48 | general classification student.
| | 01:51 | In programming we would say that each student
is an object or an instance of the class student.
| | 01:56 | They are all unique but they
have something in common too.
| | 01:59 | Now that we understand that
everything in Ruby is an object, let's take a
| | 02:02 | look at these basic object types that exist in
Ruby and begin learning to program with them.
| | Collapse this transcript |
| Variables| 00:00 | In this movie, we're going to talk
about variables in Ruby and I'm sure that
| | 00:03 | you're going to think that I've
already lied to you because I told you that
| | 00:06 | everything in Ruby is an object.
| | 00:08 | But here I am. I'm going to talk about
variables and variables are not objects.
| | 00:12 | They are a rare exception.
| | 00:13 | It's kind of strange that we're going
to start out talking about it, but we're
| | 00:16 | going to use variables a lot, so
we need to go ahead and cover it.
| | 00:18 | Variables are just part of the Ruby language.
| | 00:20 | Variables are going to be used to keep
track of our objects and to give us an easy
| | 00:24 | way to talk about those objects and
reference them while we are programming.
| | 00:27 | We can treat variables just like
objects because once a verbal is assigned an
| | 00:31 | object as a reference,
it acts just like that object.
| | 00:35 | So, a variable always either be
undefined or will act like an object.
| | 00:39 | So, variables will seem like
objects even though they're not.
| | 00:42 | Variables work pretty much like the
variables that you had back in algebra class,
| | 00:45 | except that we need to assign a
value to them before we can begin using them.
| | 00:50 | Let's take a look.
| | 00:50 | I'm going to open up an IRB session
and let's go ahead and use our first
| | 00:55 | variable. We will just call it x,
just like we had in algebra.
| | 00:58 | But like I said, we want
to assign a value to it.
| | 01:00 | Let's try x+2, just to see what that gives us.
| | 01:02 | x is undefined,
it doesn't know what to do with it.
| | 01:05 | We need to assign a value for it.
| | 01:06 | So x=1. Now we can use our up arrow
and go back to x+2 and now x has a value.
| | 01:13 | So that's how variables are going to work.
| | 01:14 | It just stores the object 1. 1 is an object.
| | 01:18 | We'll talk little more
about that in the next movie.
| | 01:20 | But for now, just notice how x is a
variable that is pointing to an object.
| | 01:26 | Now, 2 is also an object,
and 3 that gets returned by x+2?
| | 01:31 | That's also an object.
| | 01:33 | In fact remember when we said puts x+2
that nil that we got back is also an object.
| | 01:39 | So, really and truly, everything is
going to be an object in Ruby except for
| | 01:43 | these variables which are just
used to allow us to point to objects.
| | 01:47 | Now, all programming language
have a variable naming convention.
| | 01:51 | A lot of variables have a start with
the dollar sign in a lot of languages.
| | 01:54 | In Ruby that's not true.
| | 01:55 | All we have to do is have a
all lower case, underscored name.
| | 01:59 | So first variables equals 3, okay.
| | 02:04 | That's a well named variable in Ruby.
| | 02:07 | Now, we don't want to
put mixed case. All right.
| | 02:09 | You don't want to do something like
this, like you do in a lot of languages.
| | 02:12 | We don't want to put dashes in there.
| | 02:14 | It needs to be an underscore and typically
you would not run words together like that.
| | 02:19 | We would go ahead and make it more
readable like the English language by just
| | 02:22 | putting an underscore in there,
and that way it's nice and legible.
| | 02:25 | We can quickly read our
code and know what it's doing.
| | 02:29 | So in the same way since Ruby is
readable, we want to try for readability too.
| | 02:33 | For example, we don't want to do
aw_counter = 100. We want it to say
| | 02:38 | articles_written = 100.
| | 02:41 | So it's very clear right away what
we're talking about. We don't have to sort of
| | 02:46 | decrypt the name of our variable.
| | 02:48 | So, give your variables good common sense names.
| | 02:51 | Now lot of times in these tutorials I'm
going to be trying to show you something
| | 02:54 | quickly, so I'm going to use something
like x or maybe I might just say var=1.
| | 02:59 | That's fine because we're just
doing this for a demonstration purpose.
| | 03:02 | If I were writing an actual program,
I would want something that gave me a
| | 03:06 | little bit more of a clue as to
what was happening in the program.
| | 03:09 | Now, as I said, variables are
references that can be assigned.
| | 03:12 | So for example, a=100 and then we could
have b=a. Now, if we ask for the result
| | 03:19 | of b, which we can do just by typing a
variable on a line, it will return the
| | 03:23 | value that variable,
the object that it points to.
| | 03:26 | It's equal to 100 also.
| | 03:27 | All right, it's not equal to a,
because a is just a pointer to an object.
| | 03:31 | So, b takes on that same reference and
in fact if we do a = 50 now and we asked
| | 03:37 | for b again, be is still pointing at 100.
| | 03:41 | If you programmed in other languages before,
this probably makes a lot of sense to you.
| | 03:44 | There is one additional aspect of
variable naming that I want to touch on here,
| | 03:48 | even though we're going into a lot greater
depth about it later on and that is the
| | 03:52 | variable scope indicators.
| | 03:54 | In addition to just having a lower
case underscored word be the name of our
| | 03:58 | variable, we can also put some
additional characters in front of it that will
| | 04:02 | let Ruby know what the scope
or the variable ought to be.
| | 04:05 | In other words where it should be available?
| | 04:07 | Scope determines whether or not we have
access to these variables from inside
| | 04:11 | classes, methods, and other coded
structures and we'll talk more about it once
| | 04:15 | we introduce those structures, but it's
kind of hard to show you examples when
| | 04:18 | right now we only have
our global scope to look at.
| | 04:21 | So what we've been using so far are
local variables, ones wherewe have nothing in
| | 04:24 | front of it, and all you really need to
know for now is that variable names can
| | 04:29 | began with the $ sign or the @ the
front of it in order to give it different scopes.
| | 04:33 | So, $ sign in front of
it would give it global scope.
| | 04:36 | Putting two @ signs in front
of it makes it a class variable.
| | 04:39 | Putting one @ sign in front of it, it
becomes an instance variable and we'll be
| | 04:42 | working with these later on.
| | 04:44 | For now just know that these are
all legitimate ways that you can name
| | 04:47 | your variable in Ruby.
| | Collapse this transcript |
| Integers| 00:00 | In this movie we are going to take a
look at the Ruby object type integers.
| | 00:03 | Now, integers are just simply numbers,
and numbers are mostly commonsense.
| | 00:08 | But in Ruby, numbers are actually
divided into two major categories.
| | 00:12 | We have integers and then we have
floating-point numbers, which are called
| | 00:15 | floats for short, and they are
better known outside of programming as
| | 00:18 | being decimal numbers.
| | 00:20 | Ruby is going to separate
them out into two categories.
| | 00:23 | Let's take a look at integers now.
| | 00:25 | I am going to open up irb.
| | 00:28 | We were working with integers
before when we had 1+1 or we had x=2.
| | 00:33 | Those are integers, and we are
doing assignment with integers.
| | 00:35 | It's just a basic number.
| | 00:36 | That's what an integer is.
| | 00:38 | We saw that we can do other operations.
| | 00:40 | For example, we could have 4/2,
we could have 4*2, we can have 4-2,
| | 00:47 | those will all work for us.
| | 00:48 | There's also an exponential operator, two
asterisks together, and the result is 16.
| | 00:54 | That's four to the second power.
| | 00:56 | We also saw how we could do assignment, x=4.
| | 01:00 | We can do an operator with
assignment, plus equals 2, and notice what
| | 01:05 | that gives us back.
| | 01:06 | It gives us the result of the operation, 4+2.
which is 6, but it also changed x at the same time.
| | 01:13 | So that now x is going to
be equal to the result of it.
| | 01:17 | So it both incremented it
and made the assignment.
| | 01:20 | It's the same thing as if we had
typed x=x+2. It does the exact same thing.
| | 01:26 | It's just a shorthand to do it this way.
| | 01:29 | We can do the same kind of assignment
operator with all of these other things too,
| | 01:32 | the division, multiplication, minus,
all of those work the exact same way.
| | 01:36 | Just put them in front of the equal
sign and it will both perform the operation
| | 01:40 | and do the assignment at the same time.
| | 01:42 | It's kind of a nice feature.
| | 01:43 | We can also use parentheses in Ruby, (1+2) *3.
| | 01:49 | You see that it comes back with 9.
| | 01:51 | So integers work pretty much the
way we would expect them to work.
| | 01:54 | Now, let's take a look at something else.
| | 01:56 | We said that integers are objects.
| | 01:57 | So let's do .class, and that will
tell us what class it belongs to.
| | 02:03 | Before I explain this, let's try
another one, 123456789123456789.class.
| | 02:11 | Now, notice that when I did one of them,
its class was Fixnum and the other one
| | 02:15 | was Bignum. Neither one was class integer,
which is what we might have expected.
| | 02:19 | It's because integers actually belong
to one of two subclasses; they are either
| | 02:23 | put into Fixnum or Bignum,
both are subclasses of integer.
| | 02:28 | The difference is only in the way
that Ruby stores these values in memory.
| | 02:31 | It uses more memory to store these
bigger numbers, so it's going to reserve a
| | 02:36 | bigger amount of space, but to keep it
from taking up too much space all the time,
| | 02:40 | it also has the smaller more
efficient structure called Fixnum that it can
| | 02:44 | use for smaller numbers.
| | 02:46 | So we have Fixnum and Bignum and Ruby
will switch back and forth as needed and
| | 02:50 | so you will never need to worry about
the difference. Just think of both of them
| | 02:54 | as being an integer.
| | 02:55 | You can try this out with a couple of things.
| | 02:57 | If you want to multiply together two
Fixnums, you can see how long it takes for
| | 03:01 | you to get to be a Bignum.
| | 03:02 | So for example, let's say x=1234*
1234*1234, and than x.class, Bignum.
| | 03:14 | So you see it just switched back and
forth between this and there wasn't a problem.
| | 03:17 | Integers can also be negative, so
-200 is a perfectly valid integer.
| | 03:22 | 200.abs is the absolute value.
| | 03:25 | That will return the absolute value by
applying the absolute value method, which
| | 03:29 | we used in the dot notation we have seen before.
| | 03:31 | We can also have 200.next.
| | 03:33 | That's another nice method that we can
apply to integers and it will return the
| | 03:37 | next integer that comes after it.
| | 03:39 | It's the same as if we would have said 200+1.
| | 03:42 | That's really all there is to integers.
| | 03:43 | Just don't be thrown by the
Fixnum, Bignum distinction.
| | 03:46 | If you look at the class, they
are both considered integers.
| | 03:49 | But if you keep that in mind,
I think integers will be a breeze.
| | 03:51 | But in order to really understand the
way that Ruby handles numbers, we need to
| | 03:56 | not just look at the integer class, we
also need to look at the float class, and
| | 03:59 | we will do that in the next movie.
| | Collapse this transcript |
| Floats| 00:00 | In the last movie we talked about the first
type of number in Ruby, which is an integer.
| | 00:04 | In this movie we are going to
talk about the second half, which are
| | 00:07 | floating-point numbers, or for short,
we just simply call them floats.
| | 00:12 | Outside of programming you might
simply call these decimal numbers or
| | 00:15 | numbers with precision. Let's take a look.
| | 00:17 | I am going to open up irb, and let's
just try typing our first float, 12345.6789.
| | 00:25 | It has a decimal number.
| | 00:27 | This is a float, perfectly valid in Ruby.
| | 00:30 | If we hit the up arrow and then type
class after it, you will see it comes back
| | 00:34 | and it tells us that it's a float.
| | 00:36 | So this is what a float looks like.
| | 00:38 | Notice the difference between x=10,
which returns 10 to me, and y=10.0, which
| | 00:45 | returns 10.0, and x's class is a Fixnum,
while y's class is going to be a float.
| | 00:54 | So it lets it know by putting that
.0 after it that it should put it as a
| | 00:59 | different kind of Ruby object.
| | 01:01 | It basically says, look, the
precision here is important to me.
| | 01:05 | I care about the fact that it is exactly 10.0.
| | 01:10 | The other one says it's 10, plain and
simple, it's 10 and we are just going to move on,
| | 01:14 | the precision isn't important.
| | 01:16 | So notice if we now say x+1, it
comes back and tells us that x=11.
| | 01:21 | Then if we say y+1, it keeps the precision.
Even though we added an integer to it,
| | 01:28 | it says, oh, you know what?
| | 01:29 | That precision was important.
| | 01:31 | I have got a float here, so when I add
one to it, I am going to keep track of
| | 01:35 | that precision still, because it
may be important down the line.
| | 01:38 | Notice same thing if we say x+1.0.
| | 01:42 | It now says, ah, the
precision seems to be important.
| | 01:45 | We had just 10, but the fact that we
are adding a precise number to it means
| | 01:50 | that we want to keep track of it precisely.
| | 01:52 | Now, this leads us to talk about one of
the biggest pitfalls that beginners can
| | 01:57 | run into in the Ruby language,
and that is if we say 10/3.
| | 02:02 | Now, think about it for a second and
what you expect that that's going to return,
| | 02:06 | and then hit Return, and
notice that it's not what you expected.
| | 02:10 | 10 divided by three is an integer divided by
an integer, and it returned an integer to you.
| | 02:16 | It basically said I was never told
precision was important, so therefore it just
| | 02:21 | returned an integer to you.
| | 02:23 | Now, if we were instead to say well,
10.0/3 or 10/3.0, now it knows the
| | 02:31 | precision matters to us, and so
therefore it keeps the precision in the result.
| | 02:35 | So this trips a lot of people up.
| | 02:37 | 10 divided by 3 or 10
divided by 6, it doesn't matter.
| | 02:41 | It's just going to erase all the
precision, everything that comes after the
| | 02:44 | decimal point, and just return an integer to you.
| | 02:47 | Don't let that trip you up.
| | 02:49 | Now, we can also do some rounding of
our own intentionally, 12345.6789.round,
| | 02:58 | and it will round it,
following the rounding rules.
| | 03:00 | We can also tell it, "take it and
convert this number to an integer."
| | 03:04 | So we have this to_i method that will
turn our floating point into an integer.
| | 03:11 | What it does is it just
removes all the precision.
| | 03:13 | Notice it didn't actually do the rounding.
| | 03:16 | It rounded down effectively
by just removing everything.
| | 03:19 | It's the same as rounding down.
| | 03:21 | We can force it to always round down
also and sort of indicate the fact that
| | 03:25 | that's really what we mean by saying floor.
| | 03:27 | It will always round down.
| | 03:29 | Or if we always want to round up, ceil,
which is short for ceiling, ceil, and
| | 03:34 | that will always round up to the next number.
| | 03:37 | So those are some nice methods
that we can use on our floats.
| | 03:40 | The main thing is just to make sure
you don't get tripped up by this 10
| | 03:44 | divided by 3 example.
| | 03:46 | It's the one thing you really want to
just get locked into your mind as you
| | 03:50 | program in Ruby, so it
doesn't trip you up down the road.
| | Collapse this transcript |
| Strings| 00:00 | In this movie we are going to be talking
about the Ruby object type for strings.
| | 00:03 | Strings are sequences of characters.
| | 00:05 | The name comes from the fact that
the characters are strung together.
| | 00:09 | They can be a letter, a word,
a sentence, a paragraph, or even
| | 00:12 | several paragraphs.
| | 00:14 | In every case, it's still just
characters that have been strung together.
| | 00:17 | Let's take a look at how we
can define and work with strings.
| | 00:20 | I am going to open up a new irb
session and we've already seen a
| | 00:24 | string earlier, right? We had "Hello".
| | 00:29 | That's just a simple string.
| | 00:30 | It's between double quotes to let Ruby know
that this is where the string starts and ends.
| | 00:36 | We can also use single quotes the same way.
| | 00:38 | 'Hello', and that works just as well.
| | 00:41 | We could have greeting = "Hello" and target
= "world", single quotes or double quotes.
| | 00:49 | It works exact same way.
| | 00:50 | Notice that Ruby does a conversion for us here
and returns its results always in double quotes.
| | 00:55 | It's because it's the same thing; this
is just the way the Ruby represents that
| | 00:59 | value when it's output
to us. It doesn't matter.
| | 01:01 | It's stored as a string in both cases.
| | 01:05 | We can also take strings and add them
together, for example, greeting + " " + target.
| | 01:12 | "Hello world."
| | 01:14 | And we can simply add the strings
together as if they were numbers.
| | 01:18 | Now this is a common theme in Ruby
where the syntax for something like addition
| | 01:22 | is used in a commonsense way somewhere else.
| | 01:25 | You can't actually add letters together,
but it totally makes sense that the
| | 01:28 | plus notation should smooch these
together into new string in an additive way.
| | 01:32 | For example, we can also multiply
strings, "Gabba" *5 is going to be
| | 01:38 | "GabbaGabbaGabbaGabbaGabba".
| | 01:40 | Now notice that there is a difference
if we do 1 * 5, which is 5, and if we do
| | 01:45 | the string '1'* 5, which is
going to return "11111" to us.
| | 01:50 | So it's not going to convert
strings into integers for us.
| | 01:53 | We're going to need to tell it
explicitly if we want to swap.
| | 01:55 | Otherwise, it's gladly going to
just multiply out that string for us.
| | 01:59 | Now if we have a single quoted string
like 'I'm escaped.' How is Ruby supposed
| | 02:06 | to know where the string starts and ends?
| | 02:09 | It's going to see the first single
quote and then when it sees the second one,
| | 02:12 | it's going to think
that's the end of the string.
| | 02:14 | So what we are going to need to do, we
call escaping it, and that's putting a
| | 02:16 | backslash in front of it, to let
Ruby know this is a literal apostrophe
| | 02:22 | inside of these quotes.
| | 02:23 | It's not the end of the string,
and notice it takes that away when
| | 02:27 | it does its conversion
to this double quoted version.
| | 02:30 | The same thing is true for double quotes though.
| | 02:32 | Let's say we had double quotes.
| | 02:35 | "I said," we don't
need to escape that anymore, "I'm escaped."
| | 02:42 | We are going to need to put those
backslashes in front of these two to let it
| | 02:46 | know that those are literally meant
to be quote marks inside of our string.
| | 02:51 | Now it's going to keep those in there,
when it returns that value to us.
| | 02:55 | But it's a way of letting you know
these are actual quotes inside there.
| | 02:58 | Of course, if we also needed to have
an actual backslash in there, we would
| | 03:03 | put in two backslashes.
| | 03:05 | Let's say we just put at the beginning
here the number 3 slash slash and you'll
| | 03:11 | see that it kept that in there,
but this is a literal single slash.
| | 03:16 | If we actually output
that value, let's do it up here
| | 03:19 | with a puts, you'll see
that we get a single slash back,
| | 03:26 | and we get our single double quotes here,
when it actually outputs it. Okay.
| | 03:31 | Now I know the 3 in front of it is nonsense.
| | 03:33 | Now there is another very important
difference between single quotes and double quotes,
| | 03:38 | and that's the double quotes
strings do some extra evaluation that
| | 03:41 | allows us to use
escape characters inside them.
| | 03:43 | So for example, if I've puts " ", and inside I
can put the escape character that is for a tab.
| | 03:49 | So that's a tab and then I'll do an a
and then another tab followed by b, and
| | 03:55 | then I'll do a line return, which is
nc, and then another line return nd.
| | 04:01 | Notice what that puts, and there we go.
| | 04:04 | You see the tabs are in there
and the line returns are in there.
| | 04:07 | If we were to trade that for instead
having single quotes, notice now what we
| | 04:12 | get back is as if that was just literal text.
| | 04:16 | So that the double quoted version
is going to do that extra evaluation.
| | 04:20 | Even better than that though is that
double quoted strings allow you to drop
| | 04:25 | in variables to be evaluated. puts,
and then inside double quoted strings,
| | 04:32 | I want to say we'll put the pound
symbol or the hash symbol followed by open
| | 04:37 | curly braces, greeting, which is the variable
we defined earlier, we'll close our curly braces.
| | 04:43 | I'll put a space, and we'll do the same
thing again for target, and now it will
| | 04:48 | drop in those values.
| | 04:50 | Let me put a period at the end.
| | 04:51 | I want to say Hello world.
| | 04:53 | So you see what it did.
| | 04:54 | It evaluated that inside those double quotes.
| | 04:57 | So now if we were to make those instead single
quotes, you'll see that it took it literally.
| | 05:04 | It did not do that extra evaluation.
| | 05:06 | Now we can put any Ruby
expression inside those braces.
| | 05:10 | So, for example, puts, 1 plus 1 is
equal to, and then inside here, let's ask it
| | 05:18 | to tell us what is 1 plus 1? Here we go.
| | 05:20 | 1 plus 1 equals 2.
| | 05:23 | So it does the Ruby evaluation inside
those braces and then puts the value inside
| | 05:28 | the string and that only
works with double quoted strings.
| | 05:30 | Let's take a look at some of the
methods we can use with strings. We saw
| | 05:33 | one earlier, we had hello.reverse, and
we also have capitalize, we also have
| | 05:41 | downcase, downcase, of course we have upcase,
and length, and you'll see it returns 5 to us.
| | 05:54 | That's how long the string is,
how many characters are in it.
| | 05:57 | I think all those are pretty commonsense.
| | 05:58 | The one thing I do want to show you
though is that if we take Hello, and let's
| | 06:03 | say we take the reverse method, there we
are, Hello reverse, and then after that
| | 06:09 | we ask it to upcase,
you'll see that it does both.
| | 06:12 | So we can daisy chain these methods together.
| | 06:15 | So reverse.upcase.length, for example.
| | 06:17 | Of course, the length obviously is still 5.
| | 06:19 | It hasn't changed, but the point is that
every time we start with our object,
| | 06:25 | we apply the reverse method to the
object, and then we return an object.
| | 06:30 | Hello, backwards, and then that
returned object gets the upcase method applied
| | 06:36 | to it, and then the returned object from
that gets the length method applied to it.
| | 06:40 | So each time we're returning an object
and applying a new method, and that's why
| | 06:44 | it's so great that everything in Ruby
is an object is because we can do this
| | 06:47 | kind of thing to it.
| | 06:48 | And of course, daisy chaining these
methods together applies to all objects in
| | 06:52 | Ruby, not just strings.
| | Collapse this transcript |
| Arrays| 00:00 | In this movie we are going to talk
about the Ruby object type for arrays.
| | 00:04 | If you're familiar with arrays from
other programming languages, Ruby arrays
| | 00:07 | work very much the same way.
| | 00:08 | But if not, let's first
talk about what is an array.
| | 00:11 | An array is an ordered integer-
indexed collection of objects.
| | 00:15 | That's a very fancy way of saying that
we can take objects and put them together
| | 00:18 | in order, and keep their position in
the same order, and we can refer to those
| | 00:23 | objects by their positions.
| | 00:25 | That's what that integer-indexed part is.
| | 00:27 | We can say give me the first object,
give me the fifth object, and so on,
| | 00:31 | because they are going to be indexed
according to what position they hold.
| | 00:34 | One good way to think about arrays is
they are like those expanding file folders
| | 00:38 | you get that you might put your bills in,
and you might put your electric bill
| | 00:41 | in the first pocket, and your phone bill
in the second pocket, and your mortgage
| | 00:45 | payment in your third pocket and so on.
| | 00:47 | You have a preset order, and you
can put things in and out of pockets.
| | 00:51 | You can say put this in the third pocket or
take that out of the fifth pocket, and so on.
| | 00:55 | That's the way that arrays work.
| | 00:57 | And the file folder is a good analogy,
because some pockets can be empty.
| | 01:00 | So we could have something in the first
pocket and the third pocket, but not in
| | 01:04 | the second pocket, and that
would just be an empty one.
| | 01:06 | In our case, it would be nil
when we are working with Ruby.
| | 01:09 | Now the things that can go in an array
are any kind of object, any object at all.
| | 01:14 | That's strings. That's numbers.
| | 01:16 | That's more arrays.
| | 01:17 | That can be larger or more complex
objects and classes that we are going
| | 01:21 | to learn about later.
| | 01:22 | It can be mixed types as well.
| | 01:24 | We don't have to just have an array of
strings or numbers. We can mix them together.
| | 01:28 | Now arrays are going to be very, very
powerful and useful for us, and we are
| | 01:31 | going to be using them a lot, especially
when we are start working with lots of data.
| | 01:35 | Imagine for a moment that we have an
accounting program that has an array of all
| | 01:38 | the customers that have come to our shop,
and we can add to or select from each
| | 01:43 | of those customers in that array.
| | 01:45 | Then each one of those customers could
also have an array of items that they
| | 01:48 | purchased from the store or payments
that they've made, and we can add to and
| | 01:52 | select from those as well.
| | 01:54 | And it will keep all of that data
organized, and we'll be able then to move
| | 01:58 | to the data one item at a time,
either searching for records or sorting
| | 02:02 | records, that kind of thing.
| | 02:04 | Once you put into practice,
I think it will become very clear.
| | 02:07 | So I am going to start up by opening up
irb and once I am in there, I am going
| | 02:11 | to just create a new array, and I am
going to assign a variable data_set equal to,
| | 02:15 | and for our array, we use
the square bracket notation.
| | 02:19 | Open square brackets and close
square brackets, that's an array.
| | 02:21 | In fact, this is an empty array that
I've specified, and that's perfectly
| | 02:26 | legitimate. I can do that.
| | 02:27 | It's an array with nothing in it, empty pockets.
| | 02:30 | Then I could also put things in the pockets.
| | 02:32 | Let's just drop in here, and let's put
in a couple of strings, a, b, c, and now
| | 02:40 | it holds those together, and it keeps them in
order, so they will always stay in that order.
| | 02:45 | And we can pull certain items out of
the array to work with them by asking the
| | 02:50 | array to return a certain item.
| | 02:52 | So data_set, and then inside parenthesis
immediately after the data_set with no equals.
| | 02:59 | We are going to specify
the position that we want.
| | 03:02 | So I am going to say position 1,
and notice that returns back b to me.
| | 03:07 | This is a very important thing about arrays.
| | 03:09 | If you've never worked with arrays
before, this will take some getting used to.
| | 03:12 | If you have, I am sure
you're already familiar with this.
| | 03:14 | All arrays are indexed starting with zero,
so a is not in position 1. a is in position 0.
| | 03:23 | So in order to get that back,
we'd asked for data_set 0.
| | 03:26 | That gives us a, or if we would've asked
for 2, we'll get back c. Go ahead and
| | 03:32 | notice that if we asked for 3, it tells us nil.
| | 03:35 | That's because even though there's
nothing in that fourth pocket, the third index,
| | 03:39 | so it just returns nil to us.
It just says there is nothing in it.
| | 03:42 | It's a nice feature of Ruby, that it
doesn't give us an error because we've
| | 03:45 | requested something that's not in our array.
| | 03:48 | We don't have to check and see how long it is.
| | 03:49 | It just says there's nothing there.
| | 03:51 | I have no value to give you.
| | 03:53 | Now we can set values the same way.
| | 03:55 | Let's go ahead and let's just set our
position 0 equal to, we'll make it d.
| | 04:02 | So it returns d to me.
| | 04:04 | That's the return value of the operation.
| | 04:06 | If we want to see what's actually in the
data_set, we have to once again ask for
| | 04:11 | data_set, and it will return the entire thing.
| | 04:13 | We see now that a has been replaced with
d, so we said, okay, in position 0, put d,
| | 04:19 | which of course is going to displace
the a, so it gets thrown away, and the d
| | 04:24 | goes in there instead.
| | 04:25 | There is also another nice operator,
which is the Append operator, and the symbol
| | 04:30 | for it is two less than signs together.
| | 04:33 | If we do the less than less than and
then another string, what that does is
| | 04:37 | it appends it on to the end and you can see it
returned as its return value, the full array.
| | 04:42 | So now we have d, b, c, and then e.
| | 04:46 | If we wanted to take a value out of
the array, let's go back and just make
| | 04:51 | value 1 be nil, and then if we ask
for a data_set again, you'll see now it
| | 04:57 | holds that first place with nil, all
right, which is nothing, and that's how it
| | 05:01 | knows that there's something in
pocket 0 and something in pocket 2, but
| | 05:04 | nothing in pocket 1.
| | 05:06 | Now that doesn't clear out the whole array.
| | 05:08 | If we wanted to actually clear the
array, we have a couple of options.
| | 05:11 | One is we can do data_set clear,
and that returns an empty array.
| | 05:15 | Let's do data_set. You'll see that it is empty.
| | 05:18 | The other we'd have done the same
thing is if we'd done data_set equals, and
| | 05:22 | just set it back to an empty array,
just like we did to initially start.
| | 05:27 | Now notice though if we said data_set
equals nil, that's a different thing.
| | 05:32 | Now it's no longer an array.
| | 05:34 | Let's go back here.
| | 05:34 | Let's do this data_set, and then data_
set.class, you'll see it's an array.
| | 05:40 | If I said data_set equal to nil,
and then ask for its class.
| | 05:43 | It comes back and says the class is nil.
| | 05:45 | So it's actually a different thing,
an empty array, and having nothing are
| | 05:49 | two different things.
| | 05:51 | Now that we know the basics of how to
create an array, how to put items into and
| | 05:55 | out of an array, there are lot
more things we can do with them.
| | 05:58 | They're really powerful, so much so
that we're going to talk more about how
| | 06:01 | we can manipulate arrays in the next movie.
| | Collapse this transcript |
| Array methods| 00:00 | In the last movie we saw the
fundamentals of creating an array, putting objects
| | 00:04 | into it, and taking objects out.
| | 00:06 | But there is a lot more that we
can do to manipulate with arrays.
| | 00:08 | So I want to spend another movie really
looking at some of these array methods,
| | 00:11 | to see how they work.
| | 00:12 | I am going to open up irb, and
let's go ahead and just create an array.
| | 00:17 | I am just going to call it array = 1,2,
3,4,5, and I am going to create another one
| | 00:24 | I will call array2.
| | 00:26 | I know it's not a very descriptive name,
but for our purposes this will work.
| | 00:30 | I just want to show you that this is 1,
and let's put in 2, and then 3.0, and
| | 00:37 | then while we are at it let's go ahead and
put in a, b, and last of all, let's put in dog.
| | 00:46 | There we go.
| | 00:48 | I want to show you, first of all, with
that array2 that we can mix these types
| | 00:51 | in there, and the array doesn't care.
| | 00:53 | We saw how we can return different values.
| | 00:55 | It works exactly the
same way with the mix types.
| | 00:59 | Now, we have two arrays that we can work with.
| | 01:01 | The first thing I want to show you is
that we can do inspect, array.inspect.
| | 01:06 | You can see that it just returns back
to me the array, which is a nice way to
| | 01:11 | sort of see it and see what's going on.
| | 01:13 | Now, we can just say simply array and
that returns the value of the array, but
| | 01:17 | that's not a string.
| | 01:19 | The one above it is actually a string.
| | 01:20 | You see those double quotes.
| | 01:21 | So when we are inside a program and we
are programming. We want to be able to
| | 01:25 | put that version of it.
| | 01:27 | Let's try puts array, and
you will see what it gives us.
| | 01:31 | If we do puts array, that's what it gives us.
| | 01:33 | If we do puts array.inspect, it gives us this.
| | 01:37 | So just keep in mind that you can use that
to sort of peek at what's inside your array.
| | 01:40 | That's especially useful if you
have got something like this complex
| | 01:44 | array that's in array2.
| | 01:47 | If we were to just simply do puts
array2 by itself, you will see that it gives
| | 01:51 | us this, which doesn't really show us
the structure. a and b are just listed out
| | 01:55 | on separate lines, when in fact
they are an array within the array.
| | 01:59 | There is also another version that we can
use which is let's do array2 to string.
| | 02:05 | So 2_s is turned into a string.
| | 02:09 | That just smashes everything together.
| | 02:10 | So it doesn't give us this nicely
formatted string that inspect gives us.
| | 02:14 | Instead it joins them together.
| | 02:16 | In fact, it's the exact
same thing as if we do join.
| | 02:19 | The difference is that with a join, we can
also specify what we want to join it with.
| | 02:23 | So I will use a comma space and now
it will join them together and put
| | 02:30 | commas between them.
| | 02:32 | Incidentally, we can do
the same thing in reverse.
| | 02:34 | Let's say we have x = and it's a string,
1, 2, 3, 4 and 5, and we could say y =
| | 02:41 | x.split, and split it on the commas.
| | 02:47 | So now it takes the string.
| | 02:50 | Every time it finds a comma, it says, "ah,
that's a new element" and it turns it
| | 02:53 | into an array for us.
| | 02:54 | So it returns an array, and
now y is equal to that array.
| | 02:58 | We can also do reverse on our arrays,
and you will see it just simply reverses
| | 03:02 | the order like you would expect.
| | 03:03 | It's not just for strings.
| | 03:05 | Let's go back to our original array
here, 1,2,3,4,5, and let's put at the end,
| | 03:10 | array, we will do the append that we learned
before, and at the end we will append a 0.
| | 03:16 | So then we got 0 at the end.
| | 03:17 | Now we can say array.sort, and
it will sort our array in order.
| | 03:22 | Now, we can't sort mix types,
not using just a simple sort.
| | 03:26 | We can learn more complex ways to do it later.
| | 03:28 | But when I have that very complex array
that has some floats, and some integers,
| | 03:32 | and some strings in there.
| | 03:34 | It's not sure how you want to sort that.
| | 03:36 | There is no simple numerical order or
alphabetical order that it can follow.
| | 03:40 | So we would have to write something
more complex and we can learn to do that.
| | 03:42 | There is also unique. Let's say array.
| | 03:46 | Let's again put at the end of it.
| | 03:47 | This time we will put a 3.
| | 03:50 | So you see that it has now got
this 3 at the end, so it has two 3s.
| | 03:53 | I can say array.uniq for unique, no 'ue'
at the end, and it will return to me an
| | 03:59 | array that has no duplicates in it.
| | 04:01 | Now, it didn't actually change the array itself.
| | 04:03 | It's not the same as when we appended it
on, it actually changed the array.
| | 04:07 | This just says return me another version,
a new array that has no unique values in it,
| | 04:12 | while leaving the other one alone.
| | 04:13 | In fact, if we would do unique with an
exclamation point at the end, it would
| | 04:18 | actually change it in place.
| | 04:21 | So there we go, array.
| | 04:23 | Now it's permanently changed.
| | 04:24 | It has been deduped.
| | 04:26 | Now, we saw how we could
set values to nil earlier.
| | 04:30 | We also have array.delete_at, and
let's say delete at position 2, and remember
| | 04:37 | that's going to be the third item.
| | 04:39 | So it returns what it deleted.
| | 04:41 | It deleted number 3, so 3 was returned.
| | 04:44 | If we take a look at the array, you will
see it didn't set it to nil. Instead
| | 04:49 | it pulled it out of the array
and shifted everything over.
| | 04:52 | So it actually removed it
from the order completely.
| | 04:56 | The other version left nil there
as a placeholder in that position 3.
| | 05:00 | Now, that's all great if we know the
position, but what if we don't know what
| | 05:03 | position something is at, and
we want to delete something?
| | 05:06 | We can also just use delete by itself.
| | 05:09 | Let's say we will delete
number 4 and now it returns 4 to us.
| | 05:14 | But if we ask for the array, it went
through and it found the number 4,
| | 05:18 | not position four, the number 4.
| | 05:20 | Now, the fact that both of these
deletes return the value that's being deleted
| | 05:25 | is nice, because we can sort of
catch it as it's coming out of there.
| | 05:27 | We can say pull it out of there, and
while it's coming out, let me store it in
| | 05:32 | another variable that I might want to use.
| | 05:35 | We saw how we could
have array with the append.
| | 05:37 | We could append something
at the end. Let's say 3.
| | 05:40 | We can also do the
same thing using array.push.
| | 05:44 | So we will push something onto the end.
| | 05:47 | Let's push a 4 onto the end. There we go.
| | 05:50 | We can do array.pop and it will take
the last element off of the array and
| | 05:55 | return it just like the delete_at did.
| | 05:57 | But it basically takes whatever is in that
last position and pulls them out of there.
| | 06:01 | We have the same thing with shift and
unshift that we will work with at the beginning.
| | 06:05 | So let's do shift first, which will
return the 1, and then there it is.
| | 06:11 | Let's do unshift now.
| | 06:13 | We will put back on the 1.
| | 06:14 | You can see the 1 goes back on there.
| | 06:17 | There is a lot more to learn with array
methods and you can take a look at that
| | 06:21 | Ruby documentation to see what else is there.
| | 06:23 | The one other thing that I want to show
you is that we can also add arrays together.
| | 06:27 | So array + and let's make a new array here
which is going to have 9, 10, 11, and 12 in it.
| | 06:36 | You will see what it gives us back is
that it takes the first array and just
| | 06:40 | adds those other elements on there.
| | 06:42 | Just an additive property to make one new array.
| | 06:44 | It didn't change the original array.
I would have to store that if I wanted to
| | 06:47 | capture it and say new_array =
array + and I will just do that for now.
| | 06:56 | We also have the same thing
with array -. So there we are now.
| | 07:00 | It has subtracted out those.
| | 07:02 | We could also do, for example, array - 2
and that has the same effect as if we
| | 07:06 | had done a delete searching for 2.
| | 07:08 | I think that's enough array
techniques to get us started.
| | Collapse this transcript |
| Hashes| 00:00 | In this movie we are going to take a
look at the Ruby object type for hashes.
| | 00:03 | Before we start with hashes, you will
want to make sure that you have a good
| | 00:05 | understanding of arrays, because
hashes are going to be very similar.
| | 00:09 | Hashes are an unordered, object-
indexed collection of objects.
| | 00:14 | So notice, first of all, that where an
array is an ordered collection, a hash is
| | 00:18 | an unordered collection.
| | 00:20 | That's a very important difference.
| | 00:22 | We cannot count on the order that
things are going to be stored in a hash.
| | 00:26 | And instead of being indexed by their
position and keeping track of the number,
| | 00:32 | instead we are going to keep
track of them using an object.
| | 00:35 | We call this a key-value pair.
| | 00:38 | We have one object that's the key and it
references a second object that's a value.
| | 00:43 | If you think back to the expanding file
folder metaphor that I gave you when we
| | 00:46 | were talking about arrays, well, hashes work
a little bit more like hanging file folders.
| | 00:51 | They are not in any certain order.
| | 00:53 | They can be rearranged.
| | 00:55 | Each of those file folders is going to
have a label on it, and that's how we are
| | 00:59 | going to find information.
| | 01:00 | Since we can't know what order it's in
anymore, now we are going to just thumb
| | 01:04 | through those file folders in our
hanging file folder until we find the label
| | 01:08 | that corresponds to what we are looking for.
| | 01:10 | So instead of saying well, our phone
bill is in pocket one and our electric
| | 01:14 | bill is in pocket two, instead we will
say find the thing labeled phone bill
| | 01:20 | and pull out its contents.
| | 01:21 | Its contents will be the value.
| | 01:23 | So that's a key-value pair.
| | 01:25 | So both an array and a
hash have a very good purpose.
| | 01:28 | When we want to preserve the order and the
order matters to us, we want to use an array.
| | 01:33 | When it's not so much the order that
matters, but we want the convenience of
| | 01:36 | having that label, and we want to be
able to refer to things by label instead of
| | 01:39 | trying to remember what was in
pocket number seven, I can't remember.
| | 01:44 | Well, we can put a label on it by using a hash.
| | 01:46 | So that's the two differences.
| | 01:48 | One is going to be labeled, which
will be the hash, and the array will
| | 01:51 | preserve the order.
| | 01:53 | Incidentally, in a lot of other
programming languages, hash is often referred to
| | 01:56 | as being a dictionary.
| | 01:57 | So if you are used to calling it a
dictionary in another language, Ruby is going
| | 02:00 | to refer to it as a hash.
| | 02:02 | Let's try creating one.
| | 02:03 | So I am going to open up irb.
I am going to start out by creating an array.
| | 02:08 | So we can make an example here.
| | 02:09 | I am going to make an array.
| | 02:11 | It's going to be Kevin, Skoglund, and male,
blue for my eyes, and blonde for my hair.
| | 02:22 | So there we go, now we have an
array that describes a person.
| | 02:24 | Well, that's a little bit cumbersome if
we want to remember, oh, blue, was that
| | 02:29 | the color of clothes he is wearing
today, or is that the color of his eyes?
| | 02:32 | Is blonde the color of his hair or
the color he wishes his hair was?
| | 02:36 | It's a little vague as to what things are.
| | 02:37 | So labels become important.
| | 02:39 | So instead we want to use a hash, and
a hash, instead of having those square
| | 02:43 | brackets is going to use curly braces, and
that's how we will know that it's a hash.
| | 02:47 | That's how we can recognize it right
away is that it uses those curly braces.
| | 02:51 | We are going to have key-value pairs,
and we are going to structure our
| | 02:54 | key-value pairs like this.
| | 02:55 | We will have first_name.
| | 02:58 | And that's an object.
| | 02:59 | It's a string, and it's going to
refer to Kevin. So there we go.
| | 03:03 | We have a key and a value, and we have
this equals greater than sign that points
| | 03:08 | from one to the other.
| | 03:09 | So that lets us know that this is the
label first_name that applies to Kevin.
| | 03:13 | Now we can keep going with the rest, last_
name, and we will point that at Skoglund.
| | 03:18 | There we go. Now, you could keep going and
do the rest of them for a time. I am not going
| | 03:22 | to type them all out.
| | 03:23 | I am just going to leave it at that,
because it will allow me to show you that
| | 03:26 | we can use the same notation that we
used when we were working with arrays, but
| | 03:31 | instead of providing the index that we
want, we are going to provide that key.
| | 03:35 | So it will be the string, first_name.
| | 03:38 | That's the thing that points at the
first_ name that's inside our gash.
| | 03:42 | If we wanted the last_name, the same thing.
| | 03:44 | It's a string that we are asking for.
| | 03:46 | So it's object-indexed.
| | 03:48 | Instead of being integer-
indexed, it's object-indexed.
| | 03:51 | We are asking for that object back.
| | 03:53 | Now, even though we won't use it as
often, I want to go ahead and show you that
| | 03:57 | we can also use the index method,
and we can ask for the reverse.
| | 04:01 | We put this inside parentheses, but we
use the index method and tell it return
| | 04:05 | Kevin and it will return the key to us.
| | 04:08 | We said find the value Kevin and return its key.
| | 04:11 | So it's the reverse of what we are trying to do.
| | 04:14 | Sometimes that trips beginners up,
because they are so used to using keys to
| | 04:17 | find things that when they finally say,
oh, you know what, I wish I could look
| | 04:20 | something up by its value,
they are not sure how to do it.
| | 04:23 | So we can use index to do it.
| | 04:24 | Return the index of the value Kevin.
| | 04:27 | I also told you earlier that we
could have a mixed objects in arrays.
| | 04:32 | The same thing is true for the keys
and the values that are inside a hash.
| | 04:37 | We could have the number 1 that points
to a, b, c and then a comma and our next
| | 04:46 | one, which will be 'hello', which is a
string that's going to point to 'world'.
| | 04:51 | Then let's make our next one
actually be an array. There we go.
| | 04:56 | That's going to point to a string.
| | 04:58 | We will just make it 'top',
just sort of a nonsense word there.
| | 05:01 | So now we have a mixed hash.
| | 05:04 | Notice that it switched the order around.
| | 05:06 | The order is not important.
| | 05:07 | We can't count on it
being in any particular order.
| | 05:10 | What it returned to me may
always be the same thing.
| | 05:13 | That's just because of the way it
happened to be stored in memory at
| | 05:16 | this particular moment.
| | 05:17 | We can't count on it not moving around.
| | 05:19 | We have to refer to things by label.
| | 05:21 | So we could ask for mixed, and then 1,
and it will return not the first element,
| | 05:27 | but the thing with the label that is 1.
| | 05:30 | Same thing we saw how we could do
'hello' earlier by doing a string.
| | 05:33 | So instead, I will just show you that
we could also put 10, 20 and that will be
| | 05:38 | the array that we asked for.
| | 05:40 | And it says, "oh, let me see if I can
find that as a label," and so it says "ah,
| | 05:43 | here is the array [10, 20] and so I
will return the value, which is top."
| | 05:49 | There are a lot more things
that we can do with hashes.
| | 05:51 | I am just going to show you
a couple of other quick ones.
| | 05:53 | Let's say we have mixed.keys, will
return all the keys, and mixed.values, will
| | 05:58 | return all of the values.
| | 06:00 | It will turn it into an array when it does that.
| | 06:03 | We could also have mixed.length.
| | 06:05 | I don't know if I showed you earlier, but you
can use length on an array for the same purpose.
| | 06:09 | Size is also synonymous with that.
| | 06:13 | We can also use a mixed.to an array.
| | 06:18 | That's to_a, and it turns all those
key-value pairs into array pairings.
| | 06:22 | So each key-value pair is its own array.
| | 06:26 | Last, we also have mixed.clear, and
that will just turn it to a simple empty
| | 06:31 | hash, or we could just do mixed equals,
and just empty curly braces and that
| | 06:37 | will also then just set
it back to an empty hash.
| | 06:39 | So the last thing that I just want to
show you is just if we want to set a
| | 06:43 | value inside one of these hashes,
besides just creating it, we do it just the
| | 06:46 | same way that we do with an array.
| | 06:48 | We use the square bracket notation
and then we put the label that we want.
| | 06:52 | Even if it's not something that's
in there already, it doesn't matter.
| | 06:55 | Equals and then whatever it is, so male.
| | 06:58 | You will see now it returns male to us,
but if we ask for person again,
| | 07:02 | it actually has added
that key-value pair to it.
| | 07:05 | So there is a lot more
that we can do with hashes.
| | 07:07 | I think this is enough to get us started.
| | 07:09 | Take some time and make sure that you
understand both arrays and hashes and
| | 07:12 | the difference between them, because
we are going to be using them a lot when
| | 07:15 | we program in Ruby.
| | 07:16 | It's going to be really important that you
feel like you have a good handle on things.
| | 07:19 | Don't worry if you have to look up a
lot of the methods that go with them.
| | 07:22 | That's very common.
| | 07:23 | There are so many things you can do with them.
| | 07:24 | You are going to make frequent trips
to the documentation to remember all the
| | 07:28 | powerful things that arrays
and hashes will let you do.
| | Collapse this transcript |
| Symbols| 00:00 | In this movie we are going to talk
about the Ruby data type for symbols.
| | 00:03 | And symbols are one of the most
misunderstood types by most beginning Ruby programmers.
| | 00:07 | So I want to make sure that
we have an understanding of it.
| | 00:09 | On one hand symbols are going to seem
a lot like strings, but they are not.
| | 00:13 | And sometimes they are going to seem a
lot like variables, but they are not.
| | 00:16 | What asymbol is, is a label that's
going to be used to identify a piece of data.
| | 00:21 | Now a string can also be a label too.
| | 00:23 | We just saw that when we
were working with hashes, right?
| | 00:25 | So, why do we need symbols?
| | 00:26 | Well the reason is because a symbol is
going to be stored in memory one time.
| | 00:31 | Whereas a string is going to get
stored each time. Let's take a look.
| | 00:35 | I am going to open up a irb session.
| | 00:38 | And the way that we type a symbol is that
we simply use the colon and than the name.
| | 00:43 | And the name works the same
way the variable names would.
| | 00:46 | So we can have for example test.
| | 00:48 | That is a symbol, or this_test.
| | 00:52 | So, that's a symbol that we have just declared.
| | 00:54 | It's an simple object.
| | 00:56 | Now to show you how the symbol test
is different from the string test.
| | 01:01 | Let's say this_test and then
let's ask for it's object ID.
| | 01:05 | This is a very rarely used Ruby function.
| | 01:08 | But we can ask for the object ID of
something, and you see it gives me back a number.
| | 01:12 | And that's why it's not used very often.
| | 01:13 | It's a little bit
meaningless to have this number.
| | 01:15 | But notice that when I do test.
object_id, it has a different object ID.
| | 01:22 | Well, let's do the test.
object_id again for a string.
| | 01:26 | I have a different one.
| | 01:27 | Third time, three different ones.
| | 01:28 | And it's because it created a
new string called test, right?
| | 01:31 | It didn't reuse this old one.
| | 01:33 | It's a whole new object.
| | 01:34 | This is one object, and
this is the second object.
| | 01:37 | Now, let's go up and
let's do the symbol again.
| | 01:40 | Notice that this time it's the same one,
because the symbol is stored one time
| | 01:44 | in memory, and then it goes back and reuses
that same symbol, because it's just a label.
| | 01:49 | Now for that reason symbols are going
to work really well inside hashes.
| | 01:53 | So, let's say hash = first_name
Kevin and last_name Skoglund.
| | 02:05 | Now that's a great way to label our
people, because then if we have another
| | 02:09 | person, who will use that
same label, first name, again.
| | 02:12 | We don't have to create a new
bit of memory to store it in.
| | 02:15 | So we conserve the amount of memory our
computer has to use to run our program.
| | 02:20 | Where if we use a string for the first time,
like we did back in the hash movie,
| | 02:23 | every time we created a new person,
it would create a new Ruby object and
| | 02:28 | store that in memory.
| | 02:29 | So when we really want something to be a
label, which is definitely what we want
| | 02:33 | with hash, we are going to want
to use that symbol most times.
| | 02:37 | Unless we really need to use the
string, go ahead and use a symbol.
| | 02:40 | Now there is an important point though.
| | 02:41 | Watch if I now ask for hash and ask
it to give me back it's first name.
| | 02:46 | It goes back and says no,
sorry, don't find that label.
| | 02:50 | That's because it doesn't have
anything that has a string object called
| | 02:55 | first name as a key.
| | 02:57 | What it has is something with a symbol.
| | 03:01 | So it can tell the difference between them.
| | 03:04 | And some of you may have said, wait a minute.
| | 03:06 | Let's say that I have four or five
people and I have four or five first names.
| | 03:11 | Each one of those has a
different object as the label.
| | 03:14 | And it's a different object every time.
| | 03:16 | How does hash then still
return the same thing to me?
| | 03:19 | This is because when hashes have a string as
the key, it does say well, it's good enough.
| | 03:25 | It doesn't have to be the exact same object.
| | 03:27 | It has to have the same value.
| | 03:29 | It has to be of the same
class and have the same value.
| | 03:31 | Not necessarily be the exact same object.
| | 03:34 | The other thing that I don't want you to be
confused about is that symbols are not variables.
| | 03:39 | So if we have something like test = 1,
it comes back and says nope, sorry, I don't
| | 03:44 | know how to do that. That's a label.
| | 03:46 | So up here hash is the variable.
| | 03:49 | It's a hash that has the label first name.
| | 03:52 | So you may feel like this is a variable,
but it's actually hash that's the variable.
| | 03:57 | First name is just the label that's in the hash.
| | 04:00 | So the rule of thumb is if what we are
talking about really is a word and if
| | 04:04 | the sequence of a character is
important, or if it is going to be for output,
| | 04:08 | then we are going to want to use a string.
| | 04:09 | But if it's a label that's being used to
identify a piece of data, or as we will
| | 04:15 | see later on, to pass a message around
between different parts of our program,
| | 04:19 | we will want to use a symbol.
| | Collapse this transcript |
| Booleans| 00:00 | In this movie, we are going to
talk about the Ruby type for Booleans.
| | 00:03 | Now if you have done programing before,
this is all going to be very familiar.
| | 00:07 | If not, you will just want to take a
second to understand that a Boolean is in
| | 00:10 | simple terms just going to be True or False.
| | 00:13 | Something that's one or the other.
| | 00:15 | It can't be anything else.
| | 00:16 | It's either going to be true or it's
false, and we are going to use this
| | 00:19 | for doing comparisons.
| | 00:21 | So in a program we might say for example,
if X=1, then output X, or if X is not
| | 00:29 | equal to 1, then output something different.
| | 00:32 | That's the kind of thing we are going
to be wanting to work towards in our
| | 00:35 | control flow, which we
will get to in a little while.
| | 00:37 | For now, we just want to focus on the
conditional part of that, which is a Boolean.
| | 00:40 | In order to do that, we are going
to need to know some comparison and
| | 00:43 | logic operators in Ruby.
| | 00:45 | The first of these is the equal to operator.
| | 00:47 | That's probably the most common one you
will use, and what we would use is for
| | 00:51 | example X and then = = 1.
| | 00:54 | And that would say well, if X is equal to 1,
it's a test whether or not it's true.
| | 00:59 | That's very different from X=1, which
does an assignment and it sets the value
| | 01:03 | of X=1. We are not doing an
assignment here. We are comparing it.
| | 01:07 | So you want to be careful when you are
writing these that you use the double equals sign.
| | 01:11 | That throws off some beginners.
| | 01:12 | It can especially be a problem,
because doing an assignment like that will
| | 01:16 | almost always return true.
| | 01:19 | Therefore, your test case will return
true, even though what you meant to do was
| | 01:23 | to compare and find out
whether or not it was true.
| | 01:26 | Then we have less than greater than,
less than or equal to, greater than or
| | 01:29 | equal to, I think those are
all pretty self explanatory.
| | 01:32 | Then we have got the Not Operator.
| | 01:34 | Now the Not Operator is a logical operator
and it says that something is not the case.
| | 01:39 | We can put it in front of just about
anything, including just variable names.
| | 01:43 | So !X, means that X doesn't have a value.
| | 01:46 | X is either unset or it's been set to
false or nil or something like that.
| | 01:52 | That would also return false.
| | 01:54 | Then we can see we put it
in front of the Not Equal.
| | 01:57 | That's another very common one.
| | 01:58 | If X is not equal to 1,
then we use the !=.
| | 02:03 | And then we have these other logic
operators And and Or, the double ampersand or
| | 02:07 | the two upright pipes, one after another.
| | 02:09 | Find that on your keyboard.
| | 02:10 | It's an upright line followed by
another upright line. We call those pipes.
| | 02:14 | In this case it's going to be the Or operator.
| | 02:17 | So that way we construct one set of
comparison and then say and something else
| | 02:22 | is also true, or case number 2, or
case number 3 is true. Let's try it now.
| | 02:28 | I think it will become clear.
| | 02:29 | I am going to open up a new irb session,
and let's start out by just following
| | 02:34 | that simple example. Let's say X=1.
| | 02:37 | So now we can say X==1 true,
and it returned true to us.
| | 02:42 | Now true is actually an object in Ruby.
Remember I said everything is an object.
| | 02:47 | This is our Boolean. true.class is the
TrueClass and false.class is going to
| | 02:55 | return the FalseClass.
| | 02:56 | So those are actually objects as well.
| | 02:58 | So if we say X!=1, of course that
returns false, because X is equal to 1.
| | 03:03 | Of course, we can say is X<3? Yes, it is.
| | 03:09 | Is X>3? No, it's not.
| | 03:12 | Let's try putting just the exclamation
point in front of X. We will see that it
| | 03:15 | returned False because there is an X.
With an exclamation point in front of Y,
| | 03:18 | it says, nope, Y wasn't set. Y=false.
| | 03:23 | Now, !Y=true. It's the reverse.
| | 03:28 | Think about that for a second.
| | 03:29 | Logically sometimes you get in little
tangles, and you have to kind of stop and
| | 03:32 | think your way through it.
| | 03:36 | So it would have returned False
if we just had Y. We are telling it to
| | 03:38 | find the reverse of that, which is True.
| | 03:41 | Let's try out some of our And and Or operators.
| | 03:44 | So if 1<=4 and 5 <=100, True, because
both conditions were true on both sides.
| | 03:59 | Now, notice I don't have parentheses around this.
If things start getting really complicated,
| | 04:03 | you need to group things together,
| | 04:05 | you can put parentheses around your Booleans.
| | 04:07 | Let's say if this is true, and let's do
another one here where we will say 100
| | 04:12 | is equal to or greater than 200,
which of course is not true.
| | 04:18 | So now, it tries to go
through all three of them.
| | 04:21 | The first one, it says that's true,
and the second one, that's true, and
| | 04:28 | the third one, oops! That's not true.
| | 04:30 | So the requirement was for all three to be true.
| | 04:33 | This one to be true, and this one
to be true, and this one to be true.
| | 04:36 | And since they are not, the
whole thing returns False.
| | 04:39 | So notice the way it
works its way down the chain.
| | 04:42 | We can do the same thing with Or.
| | 04:46 | Let's put an Or operator in here
for each of these. Here we go.
| | 04:53 | Now, it comes back and it says True,
because 1 <= 4, that was true, Or,
| | 04:58 | well, it doesn't matter what the rest is.
| | 05:01 | It doesn't even have to keep going,
because the first one is already true.
| | 05:05 | So one of these things has to be true.
| | 05:07 | Let's just try and change that real quick.
| | 05:10 | Let's make this into, let's say 16 < 4. Still
true, because it says well, is 16 < 4? No, it's not.
| | 05:18 | Or, maybe 5 <= 100.
| | 05:21 | Well, that is true.
| | 05:22 | And it stops right there, because it
has found one of these that's true.
| | 05:26 | Let's go ahead and make that not true,
just so we can see what happens.
| | 05:31 | Now it returns False, because
none of those things are true.
| | 05:35 | If this Or this Or this, and none
of them were true, so it returns False.
| | 05:40 | Now, there can be a lot of
different methods that we can use that will
| | 05:43 | return Booleans to us.
| | 05:45 | For example, x.nil?
| | 05:47 | No, it's not nil. y.nil?
| | 05:52 | No, it's not either. Let's try z.nil?
| | 05:56 | Undefined local variable.
| | 05:57 | But if we had said, z=nil, and
now do z.nil, we get back True.
| | 06:03 | We could also use something like Between.
| | 06:05 | Let's say the number 2, between, and
let's put in two values. Is it between 1 and 4?
| | 06:13 | Actually I need a question mark.
| | 06:14 | A lot of these Booleans are going to
have question marks in them, because it's
| | 06:17 | answering a question
and that helps you to know.
| | 06:19 | There is no problem in using question
marks in the names of methods inside Ruby.
| | 06:24 | You won't want to use them in your
variable names, but they are in the method
| | 06:27 | names a lot of times.
| | 06:28 | So is it between them? Yes.
| | 06:30 | Is it between 3 and 4? No.
| | 06:34 | A couple of more quick ones that we can do.
| | 06:35 | If we have an array, let's say
array 1,2,3 .empty? Is it empty?
| | 06:41 | No, it's not empty.
| | 06:42 | If we just had something by
itself, then of course it is empty.
| | 06:46 | We could also do 1, 2, 3,
does it include 2? Yes, it does.
| | 06:54 | Does it include 5? No, it does not.
| | 06:57 | We could do the same thing with hashes.
| | 06:58 | We can have has key and has value.
| | 07:00 | Let's just try one of those real quick,
and I will make just a real simple hash here.
| | 07:04 | There we go, 1, and b will point to 2,
and then we will take that hash and we
| | 07:11 | will just say does it has key a? Yes, it does.
| | 07:17 | Does it have key symbol a? No, it does not.
| | 07:21 | We could do the same thing with has_value.
| | 07:24 | Does it have the value 2? Yes, it does.
| | 07:29 | So there are going to be a lot more
comparisons that we can learn to do in Ruby
| | 07:33 | and a lot more of these methods
that are going to return Booleans.
| | 07:36 | The main thing is to understand the
basic concept and understand how you can
| | 07:40 | use these comparison and logic
operators to construct a Boolean expression.
| | Collapse this transcript |
| Ranges| 00:00 | In this movie we are going to talk
about the Ruby object type for ranges.
| | 00:04 | Now a range is going to
typically be a range of numbers.
| | 00:07 | Right, so let's say numbers from 1-10.
| | 00:10 | Well, we could have an array that
would contain all of those numbers or we
| | 00:13 | could simply have a range which will
say well, here is the starting point and
| | 00:16 | here is the end point. It's from 1-10.
| | 00:17 | Specially if we have something like 1-
1000, it makes a lot more sense to have
| | 00:21 | something that just tells us the
start and end point instead of trying to
| | 00:24 | construct an array or something
that has all 1000 numbers in it.
| | 00:28 | We can use a range instead.
| | 00:30 | And there is two kinds of ranges.
| | 00:31 | There is the inclusive range,
and the exclusive range.
| | 00:35 | And the notation is right there.
| | 00:36 | That's how it works.
| | 00:37 | It's just the first number and then
either 2 or 3 dots depending on which
| | 00:41 | one you want to use.
| | 00:42 | Inclusive would be the numbers
1, 2, 3, 4, 5, 6, 7, 8, 9, 10.
| | 00:47 | Exclusive range would be 1,
2, 3, 4, 5, 6, 7, 8, 9.
| | 00:52 | It would exclude the last value.
| | 00:54 | So it would be one up to but not including 10.
| | 00:57 | Now when you're programming in Ruby,
you'll find that the first one,
| | 01:00 | the inclusive range, is much more common. Why?
| | 01:03 | Because you can see both of the values
that are included so that makes it nice
| | 01:07 | and clear what's included in it.
| | 01:09 | And it's one less character to type.
| | 01:11 | So that saves us a little bit of typing as well.
| | 01:13 | But if you need to use the exclusive
range, it's there and you can use it.
| | 01:17 | You could also just do 1..9, which I
would say is probably more common and what
| | 01:21 | I would recommend to you.
| | 01:22 | Let's try them out, see how they work.
| | 01:23 | So I am going to open up irb and
let's start by just trying out that simple
| | 01:29 | inclusive range, 1-10.
| | 01:30 | You see that it returned 1..10 to me.
| | 01:33 | It didn't return all the numbers.
| | 01:35 | It didn't expand it.
| | 01:36 | It kept it as a range.
| | 01:37 | That's actually a range object.
| | 01:39 | x =1..10 x.class is a range.
| | 01:45 | Now I want to show you something here.
1..10.class is gong to give me some problems.
| | 01:50 | I set the value x equal to
that and then ask for its class,
| | 01:53 | that's not a problem.
The problem is with the dots.
| | 01:56 | The dots get a little bit confusing
to Ruby and so it says, "oops, I don't
| | 01:59 | know what you mean."
| | 02:00 | If you put simply parentheses
around it then it clears it all up.
| | 02:05 | And then it knows exactly what you mean.
| | 02:06 | So just be careful with that, with ranges.
| | 02:08 | If you try to apply one of these methods
directly to the range, it will give you some problems.
| | 02:13 | If you assign it to a value or if
you put it in those parentheses then
| | 02:17 | it will be all cleared up.
| | 02:19 | We have a couple of methods that we
can use here. We have x.begin that will
| | 02:24 | return the beginning of the range, and
end that will return the end of the range.
| | 02:30 | x.first is another one, and x.last,
and those essentially do the same thing.
| | 02:37 | Now let's try another one.
| | 02:40 | Let's say y = 1...10, another range
but this one is now exclusive range.
| | 02:45 | Let's ask it for its y.begin and y.end.
| | 02:50 | Notice that it still reports the same
beginning and end, even though it is
| | 02:56 | exclusive and inclusive.
| | 02:57 | So be careful with using begin and end
on your ranges because it may not be what
| | 03:02 | you expect it to return.
| | 03:04 | To show you that they are
actually different though I can say, for
| | 03:06 | example, x.include?(1). Yes, it does.
| | 03:12 | Does it include 10? Yes, it does.
| | 03:15 | But if I now try that on y.
Does y include 10? No, it does not.
| | 03:20 | Now what if we actually did want to expand this?
| | 03:24 | What if we wanted to expand it out so
we had all of those numbers 1 through 10
| | 03:28 | in an array that we could work with.
| | 03:29 | Well, there is a nice way that we can
do that, if we use the array notation,
| | 03:34 | which is square brackets.
| | 03:35 | We will put our x inside of it and in
front of the x we will put the asterisk.
| | 03:40 | We call that the splat operator.
| | 03:42 | So the splat operator in front of it and we
will just say z is going to be equal to that.
| | 03:48 | And there is what it returns.
| | 03:49 | It breaks it all out.
| | 03:50 | So x is still equal to just the
range but z is now equal to all of those
| | 03:54 | numbers. They have just spread it out
and expanded it into all of its values.
| | 03:59 | Now numbers are not the only
thing that we could have as ranges.
| | 04:01 | That's the most common thing we will use.
| | 04:02 | But let's say that we have 'a'..'m'.
| | 04:10 | So a to m. Actually let me do that again
and we will just set alpha equal to it,
| | 04:16 | alpha.include.
Does it include g?
| | 04:21 | Yes, it does include g because g is
in that range between those letters.
| | 04:25 | And we can do the same thing if we have
that splat operator, alpha, here we go.
| | 04:30 | And that returns all the letters a through m.
| | 04:34 | So it's a good shorthand to be able
to use especially if we're working with
| | 04:37 | numbers like 1-5000.
| | 04:38 | but that's really all there is to using
ranges. You don't use them that much but
| | 04:43 | when you do use them, they are
really a critical tool to help you out.
| | Collapse this transcript |
| Constants| 00:00 | In this movie, I want to talk
about the Ruby object-type constants.
| | 00:03 | Now we don't use constants very often in
Ruby at all, but it still is helpful to
| | 00:07 | understand them for couple of
reasons, which we will see in a moment.
| | 00:10 | It's fitting that we are going close
out with them because constants work a
| | 00:13 | lot like variables.
| | 00:14 | They are not true objects in Ruby, they
are a part of the language construct and
| | 00:18 | they point the objects the
same way that variables do.
| | 00:21 | The difference is that a constant is constant.
| | 00:24 | It should stay the same.
| | 00:25 | A variable will change over time.
| | 00:27 | So x=1, x+=1, now x=2. It's variable.
| | 00:33 | A constant should stay the same.
| | 00:35 | Only in Ruby, it's not
necessarily the case. Let's see.
| | 00:38 | We will open up irb.
| | 00:39 | We have already seen the way that we
specify a variable name like test = 1, right?
| | 00:44 | That's a simple variable name.
| | 00:46 | Well, the way we want to specify
constant names is with all capitals.
| | 00:50 | TEST equals, let's say, 2.
| | 00:52 | Two different things to
return two different values.
| | 00:55 | The first is a variable,
the second is a constant.
| | 00:58 | Now there are couple of quirks with
constants that it's important for you to
| | 01:01 | know about and that's the main
reason why I wanted to include it here.
| | 01:04 | The first is that actually anything
that begins with a capital letter at the
| | 01:09 | beginning, it's like a
variable, is considered a constant.
| | 01:12 | So Hello equals, let's just say, 10 for now.
| | 01:15 | Okay, that is actually going to be a
constant and we'll see how we can tell the
| | 01:20 | difference in one moment.
| | 01:21 | The second quirk is that, of course, if we
change a variable, test = 100, no problem.
| | 01:27 | But TEST = 100 comes back and gives
us a warning and says you've already
| | 01:32 | initialized the constant TEST.
| | 01:35 | Because this is a constant,
| | 01:36 | it did not want to let us
do that, but it did do it.
| | 01:42 | It is not truly constant.
| | 01:43 | It did go ahead, even though it raised
this warning to us, letting us know that we
| | 01:46 | shouldn't be doing this, it went ahead
and did it and the same thing is true
| | 01:50 | with Hello = 20, let's say. Same thing.
| | 01:54 | It's a constant, and that's how
we can tell that it's a constant.
| | 01:56 | So those are the two quirks that I
want to make sure I highlight to you.
| | 01:59 | These kinds of quirks are totally the
kind of thing that I can see changing in
| | 02:02 | future versions of Ruby.
| | 02:04 | In fact, your version that you're
using may handle this different already.
| | 02:08 | Because there is a little bit of quirky
behavior, this is the kind of thing that
| | 02:11 | you could totally see
changing in future versions of Ruby.
| | 02:14 | So if yours doesn't give the same
response as this, don't worry about it.
| | 02:17 | Just notice what it does do.
| | 02:20 | Most importantly what I want to make
sure is that you saw that this is the way
| | 02:22 | to name your variables, not using these
capital letters, because in that case,
| | 02:26 | it will consider a constant.
| | 02:28 | So you do want to always use all lower
case for your variable names and that's
| | 02:32 | really all there is to working with constants.
| | Collapse this transcript |
|
|
3. Control StructuresConditionals: if, else, elsif| 00:00 | In this chapter, we are going to be
talking about the control structures inside Ruby.
| | 00:04 | In the previous chapter, we were
talking about a lot of the basic object types,
| | 00:07 | but we really don't get that
far if we are just assigning different
| | 00:10 | objects to variables.
| | 00:11 | Control structures are really going to
provide the action that happens inside
| | 00:15 | of our Ruby programs.
| | 00:17 | It's what's going to decide what
takes place under certain circumstances
| | 00:21 | and the first way that we are going
to determine those circumstances is
| | 00:24 | using conditionals.
| | 00:25 | So this is, if something is true,
we are going to do one thing.
| | 00:29 | If it's not true, do something else.
| | 00:31 | Right, that's the basic thing.
| | 00:32 | We will run one set of code
under one condition, another under
| | 00:35 | different conditions.
| | 00:36 | That's why they are called conditionals.
| | 00:38 | To do that, we are going to use the
syntax of conditionals, which is going to be
| | 00:42 | if and then a boolean expression and
then end at the end and then in between
| | 00:47 | will be the code that we want to take
place if that Boolean value evaluates to true.
| | 00:51 | So if x is equal to 1 then do this bit of code.
| | 00:54 | Otherwise don't bother, just skip right past it.
| | 00:57 | That's how conditionals will work.
| | 00:59 | Now, we could write two conditionals.
| | 01:01 | We could have if x is equal to 1, then do this.
| | 01:04 | If x is not equal to 1 then do that.
| | 01:07 | But because that happens so common
we have if and else that we can use.
| | 01:12 | So if x is equal to 1, do
something, else do the alternative.
| | 01:17 | Right, it allows us just to branch it
in two simple directions based on the
| | 01:20 | true/false value of that first conditional.
| | 01:22 | But what if we want in
branch in more than one direction.
| | 01:25 | We don't want to just have a yes or no action.
| | 01:27 | We want to have more complicated choices.
| | 01:30 | Well, we have another option for that
which is elsif and that's not a typo.
| | 01:34 | It is e-l-s-i-f and that allows us to
do another test before we get to else.
| | 01:39 | So if x is equal to 1, do something, elsif and
let's say x equals to 2, then do something else.
| | 01:47 | But if neither of those is true,
then do this default else action.
| | 01:51 | That will be the fallback choice
| | 01:52 | So be careful that you spell elsif correctly.
| | 01:54 | That does trip up a lot of beginners,
especially because other programming
| | 01:57 | languages do it differently.
| | 01:59 | So an actual conditional statement
might look something like this: if x < 10
| | 02:03 | puts "Below 10"elsif x > 20 puts "Over 20"else
| | 02:09 | puts "10-20" and then end.
| | 02:12 | Now notice that we don't have any
parenthesis or curly braces or anything like that,
| | 02:17 | letting it know where
each of these sections is.
| | 02:19 | Different languages handle that
differently and a lot of them require you to put
| | 02:22 | either parenthesis or
curly braces. Ruby does not.
| | 02:25 | It's one of the nice things we can
just leave them out. The Ruby interpreter
| | 02:28 | knows that when we start a new line,
we are ready to start the code in that
| | 02:32 | if statement and it will just keep
parsing away until it gets to either
| | 02:36 | elsif, else, or end.
| | 02:38 | And when it gets to one of those,
it knows that those are magic keywords
| | 02:41 | that ought to tell it to stop that block of
code and now do another part of the conditional.
| | 02:46 | Now the tabs that are in there, where I
have it intended for each put statement,
| | 02:50 | do not signify anything to Ruby.
| | 02:52 | It doesn't use those at all.
| | 02:53 | They are only there for our
readability, so that we easily see what's being
| | 02:57 | executed between each of these parts
of the conditional. Let's try one out.
| | 03:01 | So 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:08 | So now the variable name, so we
say if name == to "Bob" and again the
| | 03:17 | indentation doesn't make a difference,
but we go ahead and do it, puts and let's
| | 03:21 | say "Found Bob" else puts
"Not Bob...". There we go.
| | 03:29 | So it was Not Bob.
| | 03:31 | Now if we did the same thing, let's hit
the Up arrow and ask it, if name equals
| | 03:36 | Kevin then let's put "Found
Kevin!" else puts "Not Kevin...".
| | 03:47 | And let's type the end.
| | 03:50 | So there it is, Found Kevin!
| | 03:51 | So you see it does match.
| | 03:53 | And elsif works the same way.
| | 03:55 | You can say if name equals to Bob again,
puts "Found him" and then elsif without
| | 04:05 | the e, name equals Mary puts "Found
her", else puts "Not Bob or Mary".
| | 04:18 | Now I know that this seems like a lot of
typing,. We have never used the Up arrows
| | 04:21 | to back and reenter old lines.
| | 04:23 | It a little bit cumbersome to do it this way.
| | 04:25 | You can put all of this into a separate
text file and then just copy and paste
| | 04:30 | into irb each time and then when you
paste in, it will execute the code.
| | 04:34 | So that's a nice way to do it.
| | 04:35 | It save yourselves typing if you're
trying to work out a particular problem.
| | 04:39 | Now notice that throughout this I did
not use parenthesis or curly braces to
| | 04:43 | tell Ruby where the blocks of code are.
| | 04:46 | Other languages do that.
| | 04:47 | They require you to use curly braces
and parenthesis in different places.
| | 04:51 | You don't have to do that here.
| | 04:52 | The Ruby interpreter knows that
when you go to a new line after an if
| | 04:55 | statement, that we are now in that if
block of code and it will keep going until
| | 04:59 | it gets to elsif, else or end.
| | 05:01 | That's a conditional keyword, so now I
know that I'm ready to do whatever that
| | 05:05 | next conditional instruction is.
| | 05:07 | So it's nice that we don't have to
type any of those or make sure that we've
| | 05:10 | closed each and everyone
that we've opened and so on.
| | 05:12 | Now Ruby also has a very nice feature
where we can put conditionals in line.
| | 05:18 | What I mean by that is I can say puts
"This is Kevin" if name == "Kevin", all right.
| | 05:27 | I have the statement I want
and then a space if the Boolean.
| | 05:32 | So we can put it at the end and it knows
because it was preceded by a statement,
| | 05:36 | it's the statement that is only
conditionally executed and that has the same effect.
| | 05:40 | Now, let's just try if this name is
equal to something it's not and now you see
| | 05:45 | that it doesn't do the put statement.
| | 05:47 | So that's a nice handy thing you have
to do, so we don't always have to write
| | 05:50 | three lines of code, if name =
"Kevin" puts "This is Kevin" end, right.
| | 05:55 | That's different lines.
| | 05:57 | Instead, we can just put it
all in one line nice and quick.
| | 06:00 | There is a few more things I want
to show you about conditionals.
| | 06:02 | We will do that in the next.
| | Collapse this transcript |
| Conditionals: unless, case| 00:00 | We have gone over all the basics
that you will need in order to work with
| | 00:03 | Conditionals, if, else and else if
will do everything that you need.
| | 00:07 | However, there are a couple of
convenience conditionals that we can also use
| | 00:11 | that work kind of like a shorthand.
| | 00:12 | We are going to look at four of them.
| | 00:13 | There is unless, case, the
ternary operator and or/or-equals.
| | 00:19 | So let's start out by looking at unless.
| | 00:21 | It looks like this, exactly like the if
statement, but instead of if it's unless.
| | 00:25 | So unless a Boolean is true, which means
the same as if not true, it's the reverse.
| | 00:32 | So instead of being if
not x > 3, it's unless x > 3.
| | 00:39 | So unless it's true, do this block of code.
| | 00:42 | Now unless can sometimes tie you in
logical knots trying to work through exactly
| | 00:46 | when it's going to be used.
| | 00:47 | So only use it if it makes a lot of sense.
| | 00:50 | If it feels right and it's convenient use
unless, but don't let it drive you crazy.
| | 00:54 | You can always just switch back to if
and then the exclamation point for not and
| | 00:59 | it's the same thing.
| | 01:00 | Now you can use else and elseif still with
unless, but there is no such thing as unlessif.
| | 01:05 | That doesn't exist.
| | 01:07 | Unless often works best in really simple cases.
| | 01:09 | When you start getting really
complex, if is the better way to go.
| | 01:12 | Now we saw how we could have multi-
layered conditionals right, if something
| | 01:17 | is true elseif something else is true, elseif
something else is true and we could keep going.
| | 01:21 | When we start to have a lot of these
the thing that ends up being better to use
| | 01:24 | as a shorthand is the case operator.
| | 01:27 | So we basically say let's look at a set
of cases when something is true, do this.
| | 01:32 | When something else is true, do that.
| | 01:34 | It's the exact same thing as the if
statements. We have just rewritten it as the
| | 01:39 | case operator instead.
| | 01:40 | Now this might not seem like it's
any shorter than what we had before.
| | 01:43 | It's actually more lines of code to do
the same thing, where it really starts to
| | 01:48 | pay dividends though is when there is a
real parallel sort of assignment where
| | 01:51 | we can say okay, when x = 1 do this,
when x = 2 do that, when x = 3 do that and
| | 01:57 | so on, and it's just right down the
line in each of these specific cases.
| | 02:01 | Now because that's when case works
best is when we are comparing a test value
| | 02:07 | against a given value.
| | 02:09 | There is also another way to use case,
which I think is probably even more often
| | 02:13 | used, which is to put the
test value right after case.
| | 02:17 | So case and then x, let's say.
When 1, do a block of code.
| | 02:23 | When 2, do a block of code.
| | 02:25 | So this really is more of a
shorthand and really saves you from having to
| | 02:28 | write 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:36 | And we can have the else statement there at
the end or we could leave that off, if we want.
| | 02:39 | Now in some other programming language
this kind of structure is called switch.
| | 02:43 | So if you've been using that, you will
want to switch over to start using case
| | 02:47 | instead, because that's
what it's going to be in Ruby.
| | 02:49 | The next one I want to show you is the
Ternary operator and what this is it's a
| | 02:53 | shortcut for simple if and else statement.
| | 02:56 | So if something is true, do one
thing, else do something else.
| | 03:01 | Well, in the case when those are
really short, especially the blocks of code,
| | 03:04 | it's just one very quick little bit
of code that we want to write.
| | 03:07 | Writing those five lines takes up a lot
of space and we can do a lot faster if
| | 03:12 | we just do it with the ternary
operator, Boolean space question mark.
| | 03:17 | Make sure you have the space there and
then a question mark, and then whatever
| | 03:20 | little tiny bit of code we want to run.
| | 03:22 | You don't want to run a
whole lot of stuff in here.
| | 03:24 | That's not what this is for.
| | 03:25 | This is only when we are just going to
do something real quick and we want a
| | 03:28 | very quick conditional.
| | 03:30 | If that's not true, the else is the colon.
| | 03:32 | So space colon space and then the
second bit of code we want to do.
| | 03:36 | So as an example, we can have puts
x == 1 and then it will either return 1 or
| | 03:43 | not 1 and that's what we will get
output, depending on the Boolean x = 1.
| | 03:46 | Now this is not highly
readable code like a lot of Ruby is.
| | 03:51 | So you really want be careful about
using it and use it only in those cases when
| | 03:55 | we are just going to do something very small.
| | 03:57 | But in those kind cases it can be a real
lifesaver and save you a lot of typing.
| | 04:01 | The last one that I want us to look
at is the or and or/or-equals operator.
| | 04:06 | Imagine that we have the simple
case where we want to say if y has a
| | 04:09 | value, then set x to it, but if not, go to z,
which is like a default value, a fallback.
| | 04:16 | So if you have y set it to y.
If not, fall back to something else.
| | 04:20 | Well, we can use the Or operator for
that and we could use it like this. x = y or z.
| | 04:24 | So if y doesn't exist, then it will be z.
| | 04:29 | Now we use that in our Booleans remember
as an or operator and you will remember
| | 04:33 | that it evaluated the first part to see
if it was true or not, and if not, then
| | 04:37 | it went to see whether the
second part was true or not.
| | 04:39 | Well, that's essentially what this is doing.
| | 04:41 | It's checking that first one. If it
doesn't exist and doesn't have a value,
| | 04:46 | then it's not true.
| | 04:47 | So it goes to the next part and it
does have a value the value z, so that's
| | 04:51 | what it sets to x. So it's worked exactly like
our Booleans do, but we can use it for assignment.
| | 04:56 | So this is a real nice shorthand.
| | 04:58 | It's a lot shorter than
writing something like this.
| | 05:01 | The other one that comes up a lot is we
want to say unless x already has a value,
| | 05:06 | set x = y. So if x has a value already,
just leave it alone, don't set anything.
| | 05:11 | But if not, we want to set it
to y. Y is like a default value.
| | 05:14 | Well, the notation for that is going to
be x and then the or operator with the
| | 05:19 | equals after it, the same way we had plus
equals, minus equals and all those kinds
| | 05:23 | of assignment operators. This is or equals.
| | 05:26 | So if x has a value, we will leave it
alone, but if not then we will set x = y,
| | 05:32 | and I think that also is a lot
shorter than writing something like this.
| | 05:36 | So all four of these are really just
shorthand methods that allow you to do
| | 05:40 | things a little bit more efficiently.
| | 05:42 | You could use if, else and elseif to
accomplish the exact same thing in every case.
| | 05:47 | Go back over it one more time
to make sure you understand it.
| | 05:50 | Go into irb, try all four of them out,
get used to how they work, because they
| | 05:54 | really are going to be big timesavers for you.
| | Collapse this transcript |
| Loops| 00:00 | We continue our discussion of Ruby's
control structures by taking a look at loops.
| | 00:04 | Now a loop does exactly what you think it would.
| | 00:07 | It loops through a bit of code over and
over and over again until you tell it to stop.
| | 00:11 | And the way that we define a loop in
Ruby is by simply having loop space and
| | 00:16 | then word do, then the code that we
want to repeat will be on a new line after that
| | 00:21 | and then on a new line once that's
done, we would have the word end.
| | 00:24 | Everything from do to end would
called a code block and we are going to be
| | 00:28 | talking more about code blocks a little
later on and going into depth with them,
| | 00:32 | because they're a really useful thing.
| | 00:33 | This really the first time we've
encountered them, so just make a mental note
| | 00:36 | this is our first code block.
| | 00:38 | Loop will take a code block and just loop
through that block over and over and over again.
| | 00:43 | In fact, if we were to go to irb and
just type in something that was a really
| | 00:47 | simple look like this, it would just
keep looping and it's called an infinite loop,
| | 00:51 | because it doesn't stop.
| | 00:52 | It just loops till infinity.
| | 00:54 | So we really need a way to have a
control over our loop, because we don't
| | 00:57 | want it to go forever, we just want
it to repeat a few times until maybe a
| | 01:00 | certain condition is met.
| | 01:02 | So the controls we will use on loops are
going to be break, next, redo, and retry.
| | 01:08 | The most useful by far is going to
be break and next and I am going to be
| | 01:11 | focusing on those here.
| | 01:12 | Break is where we will use to
terminate the whole loop and that's what you'll
| | 01:16 | use a lot, because you will basically
use a conditional to say well, if x > 10,
| | 01:21 | then break out of this loop.
| | 01:22 | We are done, we are doing looping.
| | 01:24 | The second of those commands, next, just
says immediately jump to the next loop,
| | 01:29 | start the loop over again, but
don't do anything that's below me.
| | 01:33 | Whereas break says quit
immediately, next says loop immediately.
| | 01:37 | Now redo redoes that same loop over
again and retry starts the whole loop
| | 01:43 | over from the beginning.
| | 01:44 | It really is going to apply more to some
more complex loops we will look at later on.
| | 01:48 | So let's focus on break
and next and try those out.
| | 01:50 | So let's open up irb with a simple-
prompt and let's start out by saying x = 0.
| | 01:57 | Now we are going to do a loop, loop do,
and in our loop we are going to want to
| | 02:01 | say x is going to increment by 2.
| | 02:05 | Now we will want to break out of our
loop if x >= 20, but if it's not, then
| | 02:12 | we are just going to output the value of x.
So think about for a second what this
| | 02:16 | is going to do and then go ahead and hit
Return after end, and you will see that
| | 02:20 | the loop starts. x = 0 at the very beginning.
| | 02:24 | As soon as the loop starts, x becomes
2 which is still less than 20, so we
| | 02:28 | don't break and then it outputs 2 and
then it just loops through that over and
| | 02:32 | over again incrementing x until x finally
becomes 20 and then it breaks out of the loop.
| | 02:38 | It never outputs the number 20,
because it never gets that far.
| | 02:41 | As soon as it gets to the break line,
it breaks immediately and then we are out
| | 02:44 | of our loop and our code is
done and everything quits.
| | 02:47 | Then let's try the same thing, but with next.
| | 02:49 | Let's set x back = 0 again, because it's
going to be equal to 20 at the end of that loop.
| | 02:54 | So x = 0. Let's do loop and we will do
the same thing x += 2, break also just so
| | 03:02 | we don't have an infinite loop and have
the same conditions, but now let's put
| | 03:06 | in next if x = 6 and then we will still
go ahead and output x at the end, puts x,
| | 03:14 | and then finally end.
| | 03:15 | So take a look and see what you
think that'll do and then hit Return.
| | 03:19 | So we got the same list
except for the number 6 is missing.
| | 03:22 | 2, 4 and then it jumped to 8.
| | 03:25 | That's because when it went through the
loop and x = 6 after it incremented,
| | 03:29 | it got to the line and said next if x = 6
and it immediately started the loop over
| | 03:34 | and it never got to that puts x statement.
| | 03:36 | So therefore we ended up just skipping it.
| | 03:38 | So that gives a good
illustration I think of what next does.
| | 03:41 | So let's take a look at some more complex loops.
| | 03:44 | Specifically, I want to introduce you to
while and until and these are basically
| | 03:49 | loops that just have that Boolean
break condition built into them.
| | 03:53 | So the first one is while and then are
Boolean condition, do our loop and then end.
| | 03:58 | Now there is no do, notice that. That's
little bit different. There is an implied
| | 04:02 | code block there, but there is not the
do end that we have when we have a loop.
| | 04:06 | So while something is
true, keep doing this loop.
| | 04:10 | Now the reverse of that
is until something is true.
| | 04:14 | It works the same way as if and unless,
you'll remember that unless is the
| | 04:18 | same thing as if not.
| | 04:19 | Well, until is while something is not true.
| | 04:23 | But other than that it works exactly
the same way, and which one you decide to
| | 04:26 | use really just depends on what you
are trying to accomplish and which one
| | 04:29 | just feels more natural and fits with the
English language syntax of what you are trying to do.
| | 04:34 | So to give you the concrete example
of how that while loop works,
| | 04:37 | let's take another look at that loop that we just
worked on an irb by using the while syntax.
| | 04:42 | x = 0, while x > 20, x is going to
increase by 2 and we are going to output x
| | 04:49 | and then we will end.
| | 04:51 | So what we have done is we have taken
that break if statement and made it part
| | 04:56 | of the loop structure itself.
| | 04:57 | That's what our Boolean test up at the top.
| | 05:00 | So let's try typing that in.
| | 05:01 | Let's say x = 0 now while x > 20.
| | 05:07 | Now notice I turned it around.
| | 05:08 | Before we were working with x >= 20,
now I am doing while it's < 20.
| | 05:15 | Same thing just flipped around.
| | 05:16 | So while x > 20, x += and
then we will puts x and end.
| | 05:23 | So all I have done is remove the break.
I am not going to worry about the next
| | 05:26 | for now. We are just looking at
the simple example using break.
| | 05:29 | So let's try it out look at
the list that it gives you.
| | 05:31 | Notice up here, the last number was
18 and that was true up here as well.
| | 05:36 | Last number was 18.
| | 05:38 | Now my last number is 20.
| | 05:39 | So that's an important thing
to notice about while loops.
| | 05:42 | It matters with the value x
is at the start of the loop.
| | 05:46 | Before when we are doing our break,
it mattered what was happening inside of the loop.
| | 05:51 | We had the break after x incremented.
| | 05:53 | It went ahead and looped anyway.
| | 05:55 | Here it doesn't start the
process, if this Boolean is true.
| | 05:59 | So it's like evaluating at the very top.
| | 06:01 | In fact, the equivalent loop
statement would look like this.
| | 06:05 | Now notice that what's different
about this is that I've moved that break
| | 06:08 | statement from below the x += to above it.
| | 06:12 | That's what's different about it.
| | 06:13 | So at the very top of the loop is the
very first thing that gets evaluated.
| | 06:16 | So just be careful about
that when you're using while.
| | 06:19 | Now while and until also work the
way if does and we can use them inline.
| | 06:23 | So for example, we could have
x = 0 puts x +=, while x < 100.
| | 06:32 | So we can just do it all in one
simple line. If it is just a real simple
| | 06:34 | statement that we want to
repeat, this will work for us.
| | 06:38 | Then 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:50 | So y /= 2 until y >= 1.
| | 06:54 | So it will just keep getting smaller
and smaller and smaller, putting out the
| | 06:56 | results until finally the value is <= 1.
| | 06:59 | Now this is an interesting one for you
to review some of the things that we
| | 07:03 | talked about before, because the
numbers that it outputs might not be the
| | 07:06 | numbers that you would immediately
expect unless you remember back to those
| | 07:09 | pitfalls we have talked about.
| | 07:11 | So that's really all there is
to working with Ruby's loops.
| | 07:13 | The loops are really primitive and
really simple even when we're able to use the
| | 07:17 | while and until forms.
They are still very, very simple.
| | 07:20 | The real power in Ruby is with
another looping structure which are called
| | 07:24 | iterators and it's very
important that we look at that next.
| | Collapse this transcript |
| Iterators| 00:00 | In this movie we are going to take a look
at the Ruby Control Structure for iterators.
| | 00:04 | Now iterators work a lot like loops
which we just saw in the last movie.
| | 00:07 | The difference is that instead of just
looping, waiting for something to happen
| | 00:11 | for us to take control and to either
break out of it or to do something else,
| | 00:15 | instead with an iterator we are
going to traverse a fixed set of data.
| | 00:19 | So we can kind of know where the
starting point and the ending point is.
| | 00:21 | We basically want to say for each one of
these things do this process, do this loop, right.
| | 00:28 | So we are going to do a code block
once for each item in a set of data.
| | 00:33 | Now we can accomplish that with loops.
| | 00:34 | For example here is a While loop.
| | 00:36 | Essentially what this while loop is
doing is just outputting Hello five times.
| | 00:41 | Before trying to do that, there is a
simpler way to do it using the Ruby syntax,
| | 00:45 | which is just to say 5.times
do and then our code block.
| | 00:50 | That's a lot easier.
It is a lot cleaner.
| | 00:51 | It is easier to see what we are trying to do
and we have to write less code in the process.
| | 00:56 | This is an iterator.
| | 00:57 | Now it might not be obvious to you
how this is iterating through numbers
| | 01:01 | instead of looping.
| | 01:02 | It may look like it's just looping five times.
| | 01:04 | But it's actually not and
we will see that in a moment.
| | 01:06 | But first, let's take a look at
some of the other iterators that are
| | 01:09 | very similar to this.
| | 01:10 | 1.upto (5) and that will put Hello;
| | 01:14 | 5.downto (1) put Hello or we can use a range.
| | 01:18 | (1..5).each put Hello.
| | 01:21 | Now the last one probably makes it the clearest.
| | 01:23 | What we are saying is take each item
in this range and do this code block.
| | 01:28 | Now notice I have curly braces around
my code blocks now instead of the do end
| | 01:32 | that we were looking at before.
| | 01:34 | This is just the shorthand syntax for it.
| | 01:36 | So you will be seeing both,
both of them are code blocks.
| | 01:38 | Again we will be talking about code
blocks later on, but just make a little
| | 01:41 | footnote, do end is a code block
and the curly braces are code blocks.
| | 01:45 | Same thing. I could have
written it this way just as easily.
| | 01:48 | Now there is more to an iterator than
simply making it shorter and easier to write.
| | 01:51 | There is actually a really nice thing
where we have access to the values that
| | 01:56 | are inside that data set while we are
iterating through. Let me show you.
| | 02:00 | So here is that same example.
| | 02:02 | From 1.upto (5) do and now notice after
the do I have a little something extra.
| | 02:08 | I have an upright bar which we
call a pipe, an i and another pipe.
| | 02:11 | And then i can be anything. I
could make it X, I could make it num.
| | 02:15 | It is just a local variable that I am
going to use inside my loop to keep track
| | 02:20 | of the data that is in this data set.
| | 02:22 | So the first time through i
is going to be equal to 1.
| | 02:25 | Second time through it will be equal to two.
| | 02:27 | So it will increment. As we go through
it will grab that next value of i.
| | 02:32 | Now you can see that I am actually
outputting that there, puts Hello + and then I
| | 02:37 | will take the value of i to
strings so we can actually see it.
| | 02:39 | I am going to open up irb with simple prompt.
| | 02:42 | Let's go ahead and create that same one.
1.upto(5) and then do and we have the
| | 02:49 | upright bar pipe, right followed by
an i. I am going to go ahead and use
| | 02:52 | something different now so you can see
that can be anything, num for example,
| | 02:56 | a new line and now it's my code block.
| | 02:58 | It is a code block where I have num
available to me and num is the value of each
| | 03:04 | element as it iterates through the dataset.
| | 03:07 | So we can have puts and we will
have Hello with a space +num.to_s.
| | 03:14 | Just to go ahead and make sure because
it will be a number because that's what
| | 03:17 | we are iterating through, right?
| | 03:18 | The numbers 1 to 5.
| | 03:19 | And then let's end that and
you will see what it outputs.
| | 03:23 | Our iterator yields that value of each
of those items as it goes through into
| | 03:27 | num and we can output it.
| | 03:29 | Let's try a different
example that doesn't use numbers.
| | 03:32 | So let's say we have fruits and in our
fruits array we will put a banana and
| | 03:37 | let's put an apple and how about a pear?
| | 03:39 | So that's just a simple array of fruits.
| | 03:43 | Well now I can say fruits.each do,
so for each item there I am going to
| | 03:49 | declare the value as fruit.
| | 03:50 | Let's go ahead and make it
something nice and common sense, right?
| | 03:52 | It makes sense that each one as we
go through is going to be a fruit.
| | 03:55 | So as it iterates, it will pop a fruit
into that value fruit and then I can say
| | 04:00 | puts and let's say fruit
and let's just capitalize.
| | 04:06 | There we are, banana, apple and pear.
| | 04:10 | So you can see, it went through each one.
| | 04:12 | Now it also then gave me a
return value back at the end.
| | 04:15 | Don't worry about that.
| | 04:16 | That's the return value for fruits.
| | 04:18 | That's what it gives you back.
| | 04:19 | What we are interested in is the output.
| | 04:21 | What it actually did here where we went
through our loop and we iterated along each item.
| | 04:26 | Now there is another form to this
each I just want to show you as well.
| | 04:29 | Sometimes for beginners this is easy.
| | 04:31 | We say for fruit in fruits, right.
| | 04:36 | This is not the same as if we had a For
statement in another language something
| | 04:41 | like C++ or Java, PHP. They have
different kinds of For statements.
| | 04:47 | It is not the same at all.
| | 04:48 | This is for each item and we are
basically declaring a name here, same thing.
| | 04:53 | These are equivalent.
| | 04:55 | For each fruit in fruits output that fruit.
| | 04:58 | So it's exactly the same thing
just a different syntax of writing.
| | 05:01 | If it is easier for you to
remember this way, great.
| | 05:04 | If you are totally hip with this code
block thing and you are ready to do it,
| | 05:07 | then go ahead and use this fruits.each
do as a fruit and then execute whatever
| | 05:13 | is in your code block.
| | 05:14 | Now we still have access to those same
control functions that we used with our loops.
| | 05:19 | This work in iterators as well.
| | 05:20 | Break, next, redo and retry.
| | 05:23 | I am not going to show you how those
work but redo and retry are little more
| | 05:26 | useful in our iterators because now retry
doesn't just say, "hey start a loop over."
| | 05:31 | Retry says go back to the beginning of the set.
| | 05:34 | So if we have banana and then we have
apple and then we do a retry, well now
| | 05:38 | it is going to jump back to banana again and
retry starting from the beginning of the list.
| | 05:42 | And if we have our redo, same thing if
we went banana, apple, if we do a redo,
| | 05:47 | it is going to the apple again.
| | 05:48 | We will need of course to have some
branching conditional If statements in there
| | 05:52 | to make sure that we don't
just endlessly loop on one thing.
| | 05:55 | But we can use redo and retry a
little more effectively with iterators than
| | 05:59 | we could with loops.
| | 06:00 | Now there a lot of different iterators
in Ruby and I am not going to try to go
| | 06:03 | through each of them with you, but you
can look up the documentation on them.
| | 06:06 | I want to just give you a
list of what some of there are.
| | 06:08 | So we have got with Integers and Floats, we
saw how we could do times like 5 times 10 times.
| | 06:13 | Upto, downto, there is also step and
that step just basically says go from 1 to
| | 06:19 | 10, but we are going to step every 2
right, so that we could go 1, 3, 5, 7.
| | 06:25 | Range we can use each for each
other we saw. We also can use step there.
| | 06:29 | So it will go from the beginning of
the range to the end of the range by
| | 06:31 | whatever step we tell it, every
four numbers, every five numbers.
| | 06:35 | With string we also have each.
| | 06:37 | We have each line, we have each byte.
| | 06:39 | With array we can use each, each index
of the array or each item in the array
| | 06:44 | with its index, in which case we
actually get two values yielded up to the
| | 06:48 | variables that we declare inside the pipes.
| | 06:50 | So we actually put pipe and then one
variable, and then another variable then
| | 06:55 | the final pipe and we have
two values we can work with.
| | 06:57 | And then with the hash we have each
key, each value or each pair which also
| | 07:01 | yields up two values that we can work with.
| | 07:03 | Now we will be working a lot
with iterators and they will become
| | 07:06 | very comfortable to you.
| | 07:07 | I think you will also find that you use
iterators many times more than you use loops.
| | 07:12 | Iterators are going to be just much
more useful for you and there is a lot more
| | 07:15 | things that you can do with them.
| | 07:16 | Now that we have talked about the
control structure and we have touched on the
| | 07:19 | way the code blocks can be useful for
us, I want to spend a chapter talking
| | 07:23 | in-depth about code blocks and the
different methods that make use of them.
| | Collapse this transcript |
|
|
4. Code BlocksWhat is a code block?| 00:00 | In this chapter we are going to take
a closer look at Ruby's code blocks.
| | 00:03 | We briefly touched on code blocks back
when we working with loops and the iterators.
| | 00:07 | But let's start out by looking at what
is a code block and reminding ourselves.
| | 00:11 | When we had an iterator like 5 times,
we had a code block and the code block was
| | 00:15 | a block of code that we wanted to be
executed each time through the loop,
| | 00:19 | each iteration and that block of code is
defined between the do and the end.
| | 00:24 | So everything between do and end is our code
block. In this case it just simply puts Hello.
| | 00:28 | Now do end is what we use
for multiline code blocks.
| | 00:31 | That's where it really is the most
benefit because we can just keep putting lots
| | 00:34 | and lots of lines in there.
| | 00:35 | It could be a hundred lines of code
that would be executed five times.
| | 00:39 | Now if we have something that's so
simple like puts Hello, then we saw that we
| | 00:43 | can also use the shorthand
notation which is just the curly braces.
| | 00:46 | So 5.times puts Hello.
| | 00:49 | If we have something that is that
short this can be much more efficient,
| | 00:51 | cleaner and easier to read.
| | 00:53 | We also saw when working with iterators
that during each iteration we can have
| | 00:57 | the iterator yield the value up to a variable.
| | 01:01 | In this case a variable that is
declared between those upright pipes.
| | 01:04 | So the variable i would be a block variable.
| | 01:07 | And so each item in the dataset 1 to 5
would be yielded up to that variable so
| | 01:12 | that that would be its value each time
through and we would have access to that
| | 01:15 | value then while we were inside our code block.
| | 01:18 | So in our case we just puts Hello and
then we used i after converting it to
| | 01:22 | string just as output.
| | 01:23 | But we could do anything with that
value we wanted to and this block variable
| | 01:27 | declaration that we did is not
unique just for the do end syntax.
| | 01:31 | We can also use it with that
curly brace syntax just as easily.
| | 01:34 | Let's switch over to irb and try it out.
| | 01:36 | Let's open up another irb session with
simple prompt so we get that out of the way
| | 01:41 | and let's start by just creating an
array and our array will be 1, 2, 3, 4
| | 01:45 | and 5, nice and easy.
| | 01:48 | So we saw we can use an iterator like
each and then we can have a code block and
| | 01:52 | I will use num as the variable that will
be yielded up instead of i. We can name
| | 01:56 | it anything we want, puts num * 20
and then we will close our code block.
| | 02:02 | So it will iterate through the array
each time the value 1 will go up to num,
| | 02:07 | then number 2 and then 3, assigning it
to that block variable which we can then
| | 02:11 | use in our code block to multiply it by 20.
| | 02:14 | Now before we knew about blocks we
were using local variables, right?
| | 02:17 | We were just simply typing a variable like x=1.
| | 02:19 | That's a local variable.
| | 02:21 | Local variables and our block
variables are going to look very similar.
| | 02:24 | Do you remember back to when we
introduced variables in Chapter 2,
| | 02:27 | remember that I gave you the naming
conventions and local variables and block
| | 02:31 | variables look the same.
| | 02:32 | They don't have a $ sign or an @
sign in front to distinguish them.
| | 02:36 | But the reason there are two different
kinds of variables is because they have
| | 02:38 | different variable scope.
| | 02:40 | We touched on scope briefly but you will
remember I said we didn't really have a
| | 02:43 | way to talk about scope yet.
| | 02:44 | Well now we have blocks we do have a
way to start discovering what variable
| | 02:48 | scope means and how it applies.
| | 02:49 | So I have now gone through my iteration.
| | 02:51 | I have declared a local variable array.
I have declared a block variable num and
| | 02:56 | I have declared a local variable x.
| | 02:58 | Let's ask for the value of
our block variable, puts num.
| | 03:02 | You will notice that it comes back
and it says that the variable num is
| | 03:06 | undefined because it is
looking for a local variable.
| | 03:09 | That block variable
exists only inside the block.
| | 03:12 | So we only have access to it inside the block.
| | 03:14 | And that's what we mean by variable scope.
Because we have access to it inside the block,
| | 03:19 | the block is its scope, right.
| | 03:21 | We don't have access to it outside and
what it really is doing is it is using
| | 03:24 | num in the temporary sort of a way and
then discarding it at the end because the
| | 03:28 | block is done, so there is no
reason for it to keep it around.
| | 03:30 | Now that is variable scope at its
simplest, but there's three important points
| | 03:34 | that I need to make for you about scope.
| | 03:36 | The first is that even though we
don't have access to our block variables
| | 03:39 | back in our local scope, we do have access
to local variables inside the block's scope.
| | 03:45 | So I am going to hit the up arrow until
I go back to my iterator and I am just
| | 03:49 | going to make a small change here.
| | 03:50 | I am just going to put in a +x at the end.
| | 03:53 | So we are calling now this x=1 that
we have defined in the local scope.
| | 03:58 | It doesn't exists in the block variables at all.
| | 04:00 | So let's go ahead and hit Return and
try it and you will see that it does still
| | 04:03 | pull in the local variables into the block.
| | 04:06 | So that's the first point.
| | 04:07 | The second important point is
sure to confuse some of you.
| | 04:11 | Let's try doing a puts num again.
num still is undefined. I have never
| | 04:15 | defined in the local scope.
| | 04:17 | So let's try it now.
| | 04:18 | Let's say num=1 and let's try our example again.
| | 04:22 | I will just hit the up arrow and we will run it.
| | 04:24 | Now let's say puts num.
| | 04:27 | Now some of you will have gotten
the result of 5, just like I did.
| | 04:30 | But I suspect that there are also some
of you who have gotten the number 1 and
| | 04:35 | if you did, just bear with me for a
minute and we will get to explaining why.
| | 04:39 | If you got the number 5 like I did
what's happening is that Ruby is bringing in
| | 04:44 | this local value for us to use inside
the block. The same way that it brought in
| | 04:48 | the local variable x, it brought in num.
| | 04:50 | The fact that we declared it as a block
variable Ruby didn't worry about. Ruby said, Oh num!
| | 04:55 | Well I know there is already a num.
| | 04:57 | I am going to bring that variable into scope.
| | 05:00 | It is almost as if we had not
declared it as a block at all.
| | 05:03 | It is just making use of it the same way we
can use x. That's what happened for me.
| | 05:07 | Now for those of you who didn't get
that result, who got the number 1 back,
| | 05:11 | which means that it did not
change its value, it was still num=1.
| | 05:15 | That's because you are
using a newer version of Ruby.
| | 05:18 | With Ruby version 1.9, I think
actually starting with 1.9.1, it behaves
| | 05:23 | differently and if we declare this value
here, it keeps it from bringing it into scope.
| | 05:29 | It says no I really mean num
ought to be a block variable.
| | 05:34 | The fact that we have used x here still
works just the same. It is bringing in
| | 05:37 | the local scope variable.
| | 05:39 | But the fact that we have declared it
as a block variable makes it only be a
| | 05:43 | block variable and that
makes a little more sense.
| | 05:45 | So I think that's going to be an
improvement for the future, but it is a big
| | 05:48 | change and it is a big change that's
happening over the next couple of months.
| | 05:51 | So this is coming soon.
| | 05:52 | So you want to be aware of both cases
so that if you are working with a version
| | 05:56 | of Ruby that's before 1.9 that it will
have the old behavior, if you have a
| | 06:01 | version that's newer than 1.9
it will have the new behavior.
| | 06:04 | And this difference in Ruby versions
is the third point that I wanted to make
| | 06:07 | you about scope inside blocks.
| | 06:09 | Now if all of that was confusing to
you and you just want to avoid the issue
| | 06:12 | altogether, there is a very easy way
to do it, which is just to name them
| | 06:15 | different things, to name what's your
local variable and your block variables
| | 06:19 | different things and then you
won't have that kind of conflict.
| | 06:22 | And one good way to do that is
to give your local variables long
| | 06:24 | descriptive names like count=0,
| | 06:28 | then inside your array use
variables like num, i, x, a, b, c those kinds
| | 06:35 | of things that are really short and
sort of indicate that it is temporary in
| | 06:39 | nature. We are just going to
be using it inside the block.
| | 06:41 | Now there are times when you are
going to want to use things that are
| | 06:43 | descriptive inside the block because
you are going to be using it a lot.
| | 06:46 | So it might be better to use something
instead of just as a or b. But a lot of
| | 06:49 | times having a real difference between
the local variable names and the block
| | 06:53 | variable names can really help
make a good distinction for you.
| | 06:56 | Now that you understand the basis of
code blocks and we have gone over how
| | 06:59 | block variable scope works, we are
ready to take a look at some of the common
| | 07:03 | Ruby methods that are going to make
use of blocks, specifically find, merge,
| | 07:08 | collect, sort and inject.
| | 07:11 | Now there are by no means all of the Ruby methods
that make use of blocks. There are a lot of them.
| | 07:15 | But these of the most common ones and the
ones that you will get the most use out of.
| | 07:18 | And I think they also provide a good
illustration of the different ways that
| | 07:22 | blocks can come into play.
| | Collapse this transcript |
| Find| 00:00 | In this movie we are going to see how
we can use code blocks effectively with
| | 00:03 | various Ruby Find methods that allow
us to find objects inside a dataset.
| | 00:08 | There are five main Find
methods we will be looking at:
| | 00:11 | find, which also is a synonym of detect,
find all, which also has a synonym of
| | 00:16 | select and then any?,
all? and delete_if.
| | 00:22 | Now delete_if may not technically fall
under the umbrella of Find, but what
| | 00:25 | we are really doing is finding something
and then deleting it, all in one step.
| | 00:29 | So I am going to go ahead and include it here.
| | 00:31 | The thing that all of these methods
will have in common is that they are going
| | 00:33 | to take a code block and that code
block for each and every one of them is going
| | 00:37 | to be a Boolean expression.
| | 00:40 | So code block does not necessarily
have to be made up of sort of action
| | 00:43 | statements, things like puts or setting
variables and all sorts of processing.
| | 00:47 | It can be a Boolean just as easily.
| | 00:49 | I think it will make a
lot of sense once we try it.
| | 00:51 | Let's start by open up irb with a
simple prompt and let's start out by using a range,
| | 00:57 | remember we talked about ranges before.
| | 00:59 | A range 1..10 inclusive and
let's apply the find method to it.
| | 01:04 | Now we are going to need to
have a code block after that.
| | 01:05 | We know a code block is going to be the
curly braces for a simple one line code block
| | 01:09 | and I am also going to put the
upright pipes and declare a block variable of i.
| | 01:13 | So each number in the range will get
put into i as it iterates through the set.
| | 01:19 | Now it's not actually an iterator but it
does work according to the same principles.
| | 01:23 | It is going to take each value and
present it up to that block variable.
| | 01:26 | So now we need to write
a Boolean expression here.
| | 01:29 | We could just write something simple
like i =5 and then when we return it,
| | 01:35 | you'll see that it
comes back and it says ah, 5.
| | 01:38 | It went through the set and it went until
it found the item where i was equal to 5.
| | 01:42 | Now that's kind of an obvious thing
but we could have been checking for
| | 01:45 | something much more complex and we
might not have been using just numbers in a range.
| | 01:48 | We could have be using something
like an array of complex objects, where
| | 01:52 | we were checking various things as
we went through to see if they match.
| | 01:55 | But let's give another example which I
think will illustrate it a little better.
| | 01:58 | Let's erase this and instead
let's use the modulo operator.
| | 02:02 | Now if you are not familiar with
this from other programming languages--
| | 02:04 | we haven't talked it about yet.
| | 02:05 | What it does is it divides i by 3 and
returns the remainder, whatever is left over.
| | 02:11 | And so if it divides evenly
the remainder should be 0.
| | 02:14 | So what we are asking for is what
numbers are evenly divisible by 3.
| | 02:19 | So let's run that and you will see that it
comes back with the first one, which is three.
| | 02:24 | Now there are other ones that it could
have returned but it doesn't do that.
| | 02:27 | It just returns the first one and that's
why find has this synonym of being detect.
| | 02:34 | So start looking at this set and detect the
first one, so that works the exact same way.
| | 02:38 | Let's try detect again, but instead
this time let's find out what numbers when
| | 02:42 | multiplied by 3 are still between 1 and 10.
| | 02:46 | So I will have another range, 1 to 10,
and we can use include, remember we worked
| | 02:51 | with that earlier, is include in that set i*3.
| | 02:54 | So if we multiply 5 by 3 is
it still included in this set?
| | 02:58 | It came back and reported 1,
because 1 times 3 is still in that set.
| | 03:03 | It found the first one where that applied.
| | 03:06 | Now what if we don't want to just find
the first one? What if we want to find all?
| | 03:09 | So find and detect will always either
return a single object or they will return
| | 03:14 | nil if nothing is there.
| | 03:15 | We can try that real fast.
| | 03:17 | Let's say detect the number 20 and
there and it comes back and says no.
| | 03:20 | So it is always either an object or nil.
| | 03:23 | Now what if we want to
find all? Let's go up here.
| | 03:26 | Let's try our modulo again and this
time let's just say find all for everything
| | 03:32 | that's divisible by 3.
| | 03:32 | You will that it comes back this time
with an array, an array of the numbers
| | 03:37 | which are divisible by 3.
| | 03:38 | And if there had been none there,
let's say numbers which are divisible by 30
| | 03:43 | and there is none of them so
it gives us back an empty array.
| | 03:46 | So as I mention when we are listing them out,
find all also has a synonym which is select.
| | 03:51 | Let's try a select.
| | 03:53 | Let's try it with this one here.
| | 03:54 | So let's find everything where this
is true and that's going to be select.
| | 03:59 | So now 1, 2 and 3, all can be multiplied by
3 and still will not exceed the number 10.
| | 04:06 | The number 4 when multiplied by 3
will be 12 so it I outside that range.
| | 04:09 | We can also use Any and
All in a very similar way.
| | 04:12 | Let me just go back up here where we
have the divisible by 3 and instead of
| | 04:16 | using the Find All method we can use any?
| | 04:19 | So are there any in this set where this is true?
| | 04:22 | Don't return the value to us.
| | 04:24 | Return a Boolean, True or False, right.
| | 04:27 | So we are using a Boolean inside the
block and we are going to return a Boolean
| | 04:31 | as well and it returns the Boolean True.
| | 04:33 | So it is true. There are numbers
divisible evenly by 3 in our set.
| | 04:38 | We can do the same thing with all and
of course that will tell us well, are all
| | 04:42 | of them meeting this requirement?
| | 04:44 | And the answer is no, they don't.
| | 04:46 | Now delete_if is not going to work
with a range. Let's try it real quick.
| | 04:49 | Let's delete_if, if it is evenly
divisible, delete_if, there we go.
| | 04:55 | So it comes back and it says, "sorry,
a range you can't apply delete_if to."
| | 04:59 | But if you remember, know how to turn
our range into an array, you just put
| | 05:04 | the square brackets around and instead and
the asterisk, the splat operator, to expand it.
| | 05:10 | All right so and now look what it gave us back.
| | 05:13 | It is 1, 2, 4, 5, 7, 8 and 10.
| | 05:17 | It left out 3, 6 and 9.
| | 05:18 | So it is the exact same thing as doing
a find all for 3, 6 and 9, but then it
| | 05:24 | also does the extra step of
removing them from the original array.
| | 05:28 | So it is not technically a find, but
because it works on the same principles
| | 05:31 | I think it is useful to see it here.
| | 05:32 | Now just because I am using ranges
and arrays of very simple numbers to
| | 05:37 | illustrate the point, doesn't mean
you can't use more complex things.
| | 05:40 | You can detect whether a string matches
or not; you can see whether a hash has a
| | 05:45 | certain value in it.
| | 05:46 | Really any Boolean or almost any set of
objects that you have where you can go
| | 05:50 | through the set looking for something,
you can apply these same methods to it.
| | 05:54 | So just remember when you are using
them that Find and Detect will return an
| | 05:58 | object or they will return nil.
| | 06:00 | Find All and Select will return an
array of things that it finds that match.
| | 06:04 | Any will be a Boolean. Either there
are some in there or they are not.
| | 06:08 | All would be like any except they all
must meet that requirement of our Boolean test
| | 06:13 | and they will return a Boolean
True or False and delete_if will return an
| | 06:17 | array with the items removed.
| | Collapse this transcript |
| Merge| 00:00 | In this movie, we are going to take a
look at another Ruby method that's going
| | 00:03 | to make good use of code
blocks, and that's Merge.
| | 00:06 | And Merge is going to be used for merging
hashes together, and it's for hashes only.
| | 00:10 | This is not for arrays, or for
ranges or strings or anything else.
| | 00:14 | This is just a method that we
are going to use with hashes.
| | 00:16 | So let's open up irb with a simple prompt,
and let's start out by just declaring a hash.
| | 00:22 | I am just going to call it h1, real
simple. h1 is going to be equal to a, which
| | 00:28 | will point to the number 111, and let's
have b, which will point to the number
| | 00:34 | 222 and that's our first hash.
| | 00:37 | Now, let's make a second hash, h2, and
in that hash, we are going to have b as a
| | 00:42 | key for the value 333.
| | 00:46 | And let's have c as a value for 444.
| | 00:48 | Now, you can put in just
about anything you want here.
| | 00:51 | The important thing about the two is
that you'll notice that b is a key in both
| | 00:55 | of the hashes, and that's because I
want to show you what happens when we merge
| | 00:58 | them together in that case.
| | 01:00 | So all we need to do to merge the two
hashes together is h1.merge(h2) and it
| | 01:07 | returns a merge hash.
| | 01:09 | It takes the two and smashes them together.
| | 01:11 | And if they are conflicting keys, the
values that are in h2 are the values that
| | 01:16 | are going to win out.
| | 01:17 | That's what we are going to have.
| | 01:17 | So you see we end up with 333, not 222.
| | 01:20 | If we'd merged it the other way around,
you'll see that we would have ended up with 222.
| | 01:24 | All I did was switch which one
was being merged into the other one.
| | 01:28 | So this is just a real
simple merge between hashes.
| | 01:31 | It doesn't make use of a code block and
that's what I really want to illustrate here.
| | 01:35 | Now, this is just a very simple Ruby merge.
| | 01:38 | We are not using a code block yet, and
that's what we really want to see is how
| | 01:41 | to make use of a code block.
| | 01:42 | Well, we can also supply code
block optionally if we want.
| | 01:46 | So I am just going to hit the Up
Arrow to get back to this h1.merge(h2).
| | 01:50 | Now, the block in the case of merge is
only going to be called when there's a
| | 01:54 | conflict between two keys.
| | 01:56 | So when it's merging together, it has no
problems merging the A and the C keys together.
| | 02:01 | You can easily just put those in
there and there is no conflict.
| | 02:03 | But what we are going to use is
this block, it's going to be for
| | 02:05 | conflict resolution.
| | 02:07 | So we'll supply the block, and we are
going to need to declare some values here.
| | 02:11 | Now, we can call these block variables
anything we want, but there are three
| | 02:15 | values that are going to be
yielded up to us by Merge.
| | 02:18 | So it makes a lot of sense to name them
something that indicates what their purpose is.
| | 02:23 | The first one is the key, the conflicting key.
| | 02:25 | The second one is going to be the
old value, the one that's in the h1 in
| | 02:30 | our case, and the third one will be the new
value, the one that's about to be overwritten.
| | 02:35 | Now if I simply put a New here as the
way to resolve this, I'll hit Return and
| | 02:42 | you'll see that we get the same
behavior that we got up above.
| | 02:45 | If I go back, and I change it to
now be Old, you'll see that now we get
| | 02:50 | the other behavior.
| | 02:51 | It kept the old value.
| | 02:53 | The final value that we return out of
the block ought to be whatever we want
| | 02:57 | the new value to be.
| | 02:59 | So the block essentially says hey,
instead of me automatically deciding which
| | 03:02 | one wins out, let me pass you
those variables and you decide.
| | 03:07 | And at the end, what I need you to
give me back is the correct value.
| | 03:11 | Now, we can put something very
complicated in here, but ultimately what we need
| | 03:14 | to come up with is the value that
ought to went out between these two.
| | 03:18 | Now, if we did something like old times 2,
you'll see that it did that for us. old times 5.
| | 03:25 | Essentially, all we are saying is
Merge, here's what I want you to do when
| | 03:29 | you find a conflict.
| | 03:31 | So as another example let's have h1.merge
do and let's go ahead and do our key,
| | 03:39 | old, and new, just so we can keep
those straight, and now let's do if old is
| | 03:45 | less than new, then keep the
old one, else, return the new one.
| | 03:53 | So do you see what we are doing?
| | 03:54 | We are saying when there's a conflict,
pick the one that has the lower value.
| | 03:57 | I don't care which one is older or
newer necessarily or which one it came from.
| | 04:02 | I want to make sure that I end up with the
lowest value, and you'll see that it picked 222.
| | 04:06 | Now this is a little bit
of a clunky way to write it.
| | 04:08 | Actually, you probably would want
to write it using something more
| | 04:11 | efficient like merge(h2).
| | 04:13 | We'll use our in-line notation,
and I can just say K, O, N.
| | 04:19 | And that's going to indicate to me
which one is the key, the old value, and
| | 04:21 | the new, old, less than N, then return O,
otherwise return N, and that's using
| | 04:28 | that ternary operator notation that we
learned back when we were doing our conditionals.
| | 04:32 | So that's a nice shorthand for us.
| | 04:33 | It does the exact same thing, all
in one line instead of being spread
| | 04:36 | across several lines.
| | 04:38 | The last thing that I want to show you
about Merge is you'll notice that merge
| | 04:40 | did not change my original
values that I started with.
| | 04:43 | Let's go back to one of our
merges that doesn't have a block to it.
| | 04:47 | Here we are, h1.merge(h2).
| | 04:49 | If I put an exclamation point after merge.
| | 04:52 | Now, h1 has been changed. h2 is still
the same, but h1 has the bang at the end
| | 04:59 | with the exclamation point.
| | 05:00 | So it has said permanently change this one.
| | 05:03 | This is a common theme we'll see in
Ruby where this exclamation point gives us
| | 05:07 | sort of a different version of something
or maybe a supercharged version, in this
| | 05:11 | case something that makes the change permanent.
| | 05:13 | And just like the regular version of
Merge, we can also supply a block to this
| | 05:17 | version that has the exclamation point.
| | Collapse this transcript |
| Collect| 00:00 | In this movie we are going to be taking
a look at Ruby's Collect method, which
| | 00:03 | also makes use of a code block.
| | 00:05 | Collect has a synonym which is Map.
| | 00:07 | It's really up to you as to which one you use.
| | 00:09 | Sometimes I use map just when I am
trying to conserve space, maybe keep it from
| | 00:13 | wrapping around the line or something
like that, or maybe I am feeling lazy.
| | 00:16 | The Collect and Map are completely synonymous.
| | 00:18 | We can use either one, so use the
one that feels most comfortable to you.
| | 00:21 | The Collect or Map method is going
to really work the best with arrays,
| | 00:25 | hashes, and ranges.
| | 00:27 | An array is really the object that you
will use it most often with, but hashes
| | 00:31 | and ranges also work.
| | 00:32 | So I'll open up a new
irb session, simple prompt.
| | 00:37 | Now, let's create
ourselves an array to start with.
| | 00:39 | So array = 1, 2, 3, 4, 5, nice, simple
array. array.collect and then our code block.
| | 00:48 | We are going to have a block variable declared.
| | 00:50 | Let's call it i for now.
| | 00:52 | So what Collect does is it iterates
through the array, taking each item and
| | 00:58 | passing it up to i, then does
whatever we tell it to do in our code block,
| | 01:04 | applies that processing to it, and
puts that value into a new array.
| | 01:09 | Let's try it just to see. Let's say i+1.
| | 01:12 | That will be nice and easy to see.
| | 01:14 | You'll see what it does.
| | 01:16 | It took every item, and it applied
this processing to it, and returned a new
| | 01:21 | array with that processing applied.
| | 01:23 | I think that's a really good way to
think about it, is to think of that block as
| | 01:26 | being whatever processing
you want done to each element.
| | 01:30 | So let's try it again.
| | 01:32 | Instead of +1, let's do times 40.
| | 01:35 | You'll see that we get 40, 80,
120, 160, and 200 out of that.
| | 01:39 | We could do the same thing if we had
something like apple, banana, and orange.
| | 01:45 | So it's just another simple one.
| | 01:47 | Let's use Map this time, and we'll
take each fruit as it comes up and that's
| | 01:52 | what we'll call it, fruit.
capitalize. So there we are.
| | 01:59 | We capitalized each one as it went through
and it made a new array for us out of it.
| | 02:03 | Now let's try something else.
| | 02:05 | Let's say fruit capitalize if fruit = banana.
| | 02:12 | That wraps around there, but you see what I did.
| | 02:14 | I am saying capitalize it,
if the fruit equals banana.
| | 02:16 | Now notice when I get back here.
| | 02:18 | I did not get apple, and orange back.
| | 02:22 | I just got nil banana and nil.
| | 02:24 | This is a very important point
that throws off a lot of people about
| | 02:28 | using Collect and Map.
| | 02:29 | What happens here is if fruit is
equal to banana, then it capitalizes it.
| | 02:33 | Here it's returning the value of
fruit capitalized, but if not,
| | 02:38 | it's returning no value at all.
| | 02:40 | Now, we can have something that works that way.
| | 02:42 | We can say let's just erase this real quick.
| | 02:45 | So I have do and then fruit, and then
we'll start a new line, and now we'll
| | 02:50 | write if fruit = banana, then return the
value fruit.capitalize, else, return fruit.
| | 03:04 | Now it will do what we expect.
| | 03:06 | The important thing is that we do
need to return some value out of it.
| | 03:10 | So 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:17 | We need to be explicit about
that and say return that value.
| | 03:21 | So whatever comes out of our
processing, whatever value results from it, is
| | 03:24 | what's going to get put in our array.
| | 03:26 | So the value of processing fruit.
capitalize if fruit equals banana, when it was
| | 03:30 | apple, well it was not equal to
banana, so nil was the result.
| | 03:36 | So it put nil in there.
| | 03:37 | Now why didn't it just
return an array of banana only?
| | 03:40 | That's a very important point that I
want to make that I think will really help
| | 03:43 | you out when working with collected map.
| | 03:45 | You want to always keep in mind that
the number of items that go into this
| | 03:50 | Collect is going to be equal to the
same number of items that come out.
| | 03:54 | So if we take 10 things, we do processing on
them, it's going to result in 10 more things.
| | 03:59 | Now there may be some nils in some of those
spots, but there are always be 10 items back out.
| | 04:04 | So number of items in
equals the number of items out.
| | 04:07 | The other thing that you need to
remember about Collect is that even though it
| | 04:11 | works with arrays, hashes, and ranges,
it always returns an array. So let's try that.
| | 04:17 | 1 to 20 has arrange.
| | 04:19 | Let's do Collect and for each one we'll call
it num and num times 20. So there it goes.
| | 04:27 | It returns each one multiplied by 20, but
it turned it into an array at the same time.
| | 04:32 | So that's the second thing that
you don't want to throw you off.
| | 04:34 | You might think oh, I have a range, I am
expecting to get a range back or something.
| | 04:38 | No, it doesn't work that way,
and the same thing with the hash.
| | 04:40 | Hash equals let's make a real simple
hash here, A 111, and B is going to be 222
| | 04:50 | and the key C will point to 333.
| | 04:55 | Now, if we say hash.map, now with hash,
we get two things rendered up to us.
| | 05:01 | We get both the key and the value. K, V
is a common way to write that instead of
| | 05:06 | writing out key value.
| | 05:07 | Then we can decide what we want
to do with that key and value.
| | 05:10 | So I can say well, take
each one and return the key.
| | 05:14 | I get an array back of all the keys.
| | 05:16 | It's the same thing as if we ask
the hash for its keys, hash.keys.
| | 05:20 | We could do the same thing with the
value, or we could say something like value
| | 05:24 | times 20, and it returns an array
again, taking each of those values and
| | 05:28 | multiplying it by 20, or we
could do something crazy like this.
| | 05:31 | Let's say a string with the key in it,
followed by colon, and then let's go
| | 05:39 | ahead and put the value
right after it. There we go.
| | 05:43 | And then close our string.
| | 05:44 | So there we go, we get a set of
strings with the key value pairs with
| | 05:48 | colons between them.
| | 05:49 | It's still always an array that returns
back, three items in equals three items out.
| | 05:54 | If we try and put any kind conditional
in there, we really need to make sure
| | 05:58 | that we always get some kind of
useful value unless we are okay with having
| | 06:03 | nil values returned.
| | 06:04 | There is one final pitfall that
I want to show you with Collect.
| | 06:07 | Let's go back up to where we had
our apples and bananas example.
| | 06:10 | So here we are with the simple version of it.
| | 06:13 | We are just capitalizing all the fruit,
just to remind ourselves that's what it does.
| | 06:17 | Let's put Puts in here.
| | 06:19 | So puts fruit.capitalize.
| | 06:21 | So we did do the Puts, apple, banana, and
orange, but look what the return value was?
| | 06:27 | Nil, nil, nil, and that's
because whenever we do a puts, right?
| | 06:31 | Puts 1,2,3, the return value is nil.
| | 06:35 | So if you put a Put statement inside
there, you're going to end up with an array
| | 06:39 | that is filled with nils.
| | 06:41 | So if you are trying to for example take
that whole thing, and you try to say ah!
| | 06:45 | Well let's set that equal to something.
| | 06:47 | Let's say new array equals.
| | 06:51 | Now, if I say well what is the value
of new array, because like I said it's
| | 06:55 | equal to nil, nil, nil.
| | 06:56 | It did not put those values in there.
| | 06:58 | The right way to get them in there
would be not to put the Puts in there,
| | 07:02 | but just report the value back, and now a
new array is equal to what we would expect.
| | 07:06 | Just like we saw when we were
working with Merge, Collect and Map had
| | 07:10 | exclamation point versions that we can also use.
| | 07:12 | Just put an exclamation point at the
end and it will transform the array that
| | 07:15 | we are working with
| | 07:16 | so that the processing is applied in
place, and it actually replaces the values,
| | 07:21 | instead of giving you a new array.
| | 07:23 | Collect and Map are really a
powerful way to take an array and apply a
| | 07:26 | transformation to all the elements in the array.
| | 07:28 | That can be a really useful thing for you,
when you are trying to do data processing.
| | 07:32 | We want to take every item and just
apply that same transformation for it.
| | 07:35 | Just make sure that you keep in mind all
the pitfalls I have shown you here, and
| | 07:38 | I think you'll find it to be really useful.
| | Collapse this transcript |
| Sort| 00:00 | In this movie we are going to look at Ruby's
Sort method which also makes use of a code block.
| | 00:04 | Now the code blocks we have been
looking at before we've put Booleans in our
| | 00:08 | code block or we've put conditional
statements that determined whether or not a
| | 00:12 | certain value should be returned, or
we've returned a value as the result of
| | 00:16 | some sort of transformation or
processing that we have done.
| | 00:18 | Well, the Sort, we are
going to provide a comparison.
| | 00:21 | We haven't really talked about
comparisons yet, so let's look for a moment at
| | 00:24 | the Comparison operator.
| | 00:25 | Now, I also call this the spaceship
operator, because that's what it looks like,
| | 00:28 | a little flying saucer.
| | 00:30 | So we have the less than sign, the
equal than sign, and then the greater than sign,
| | 00:34 | and altogether that
makes up the Comparison operator.
| | 00:38 | The way we use it is to compare two values.
| | 00:40 | Value one on one side, value two on the other.
| | 00:43 | When it compares those, the same way
that a boolean compares two values and
| | 00:46 | returns true or false, Comparison
operator is going to do more than just
| | 00:50 | check true or false.
| | 00:51 | It's going to return -1 if
one thing is less than the other, 0 if
| | 00:56 | they're the same, or return the value
of 1 if value one is more than value two.
| | 01:02 | So Comparison operators are going to
be really useful in sorting, but we can
| | 01:05 | even use them just directly in irb.
| | 01:07 | Let's open up a new irb session with
simple prompt and let's just try 1 and then
| | 01:12 | our space ship operator or
comparison operator with 2. It returns -1.
| | 01:16 | Let's try it again, just flipping around.
| | 01:19 | It returns 1 to us, and then let's try
it 2 spaceship operator 2. So now it's 0.
| | 01:25 | That illustrates very clearly what's
going on here with the spaceship operator.
| | 01:30 | Now how would we apply it to sorting?
| | 01:32 | When we use Sort, it's going to use
the Comparison operator to decide which
| | 01:36 | direction the two values
ought to go in the sort.
| | 01:39 | So if it's -1, in other words value
one is less than value two, value one
| | 01:44 | should be on the left. It will move left.
| | 01:47 | Now obviously we are not
talking about literal left here.
| | 01:50 | We are talking about being less
than when we have an ordered set.
| | 01:54 | It's easy sometimes to
visualize it as being left.
| | 01:57 | If they're the same,
well then they are the same.
| | 01:58 | It doesn't matter which one
comes first. They're identical.
| | 02:01 | So we can just leave them wherever they are.
| | 02:03 | If it returns 1 though, meaning
that value one is more than value two,
| | 02:07 | value one will move right
to swap places essentially.
| | 02:10 | Value one is a bigger number,
so it will move off to the right.
| | 02:13 | I think it's going to make a
lot of sense when we try it.
| | 02:16 | Let's start by giving
ourselves an array that's out of order.
| | 02:18 | So array equals, and I am
just going to use 3, 1, 5, 2, 4.
| | 02:25 | That's all jumbled up.
| | 02:26 | That's our array, and an array is
always going to be maintained in order.
| | 02:30 | That's the nature of an array,
is that it's an ordered set.
| | 02:32 | So it will always be in that order,
until we perform our sort on it.
| | 02:35 | So array.sort and then we are
going to need our code block.
| | 02:40 | And the code block is going to have a
couple of things declared as block variables.
| | 02:44 | The first is going to be value
1, and the second is value 2.
| | 02:48 | That's what we will use to compare.
| | 02:50 | The Sort method will send each of these
values up to us in turn for the comparison.
| | 02:56 | So we can say V1 and then our comparison
operator V2, you could write up value1,
| | 03:02 | value2 or item1, item2, but the numbers
1 and 2 are very helpful to let you know
| | 03:08 | that we are comparing the two.
| | 03:09 | So what's happening in essence is that it's
yielding up the first two values, 3 and 1.
| | 03:14 | When those values come up to
the sort block, it says oh!
| | 03:17 | when I do my comparison, 3 is greater than 1.
| | 03:21 | It returns the value of 1 from the comparison.
| | 03:24 | Therefore 3 should move to the right.
| | 03:27 | 1 will move to the left, but 3 is going
to move to the right, and that will put
| | 03:31 | them closer to the correct sort order.
| | 03:33 | Now Ruby is not actually progressing
through each and every one of those pairs.
| | 03:37 | It has a more efficient algorithm that
it can take advantage of to do it faster.
| | 03:40 | But this describes the
behavior of what's happening.
| | 03:43 | So let's go ahead and try it and you'll
see that sure enough it does sort them
| | 03:47 | into 1,2,3,4,5. You may have already
realized that we could do array.sort by
| | 03:52 | itself, with no block and
get the exact same result.
| | 03:55 | That's the default behavior of sorting.
| | 03:57 | The reason that we use the block is so
that we can put more complexity to it and
| | 04:00 | change the behavior.
| | 04:02 | Let's say for example we
wanted to reverse sort them.
| | 04:04 | We could do that just by changing
them and saying well, now if value 2 is
| | 04:09 | greater than 1, or value 2 is less than 1,
do that comparison instead, and that
| | 04:13 | will reverse sort them.
| | 04:14 | We also have a convenience method for that.
| | 04:16 | I don't want you to feel like you
have to go to that trouble all the time.
| | 04:20 | array.sort.reverse will
return the exact same thing.
| | 04:23 | So what do I mean by
having more complexity then?
| | 04:25 | Well numbers aren't maybe
the best way to see that.
| | 04:28 | Let's try some strings.
| | 04:30 | Let's go back to our fruits that we
were working with earlier, fruits.
| | 04:33 | Let's make banana and an apple,
and an orange and a pear.
| | 04:40 | So those all have different length names.
| | 04:42 | We will go ahead and make that our array.
| | 04:44 | Now if we just say fruits.sort, it's
going to sort them in alphabetical order.
| | 04:49 | That's the default behavior of
Sort when it's applied to strings.
| | 04:53 | It's going to compare them, and
say ah, I am comparing two strings.
| | 04:55 | I am going to sort them just simply based on
this same V1, V2 comparison that we did up here.
| | 05:01 | Well, what if we want something more complex?
| | 05:03 | So for example let's say that we wanted
to sort them by the length of the string.
| | 05:07 | Not by alphabetical order
but how long the string is.
| | 05:10 | So fruits.sort, let's call the
first one fruit1, and fruit2.
| | 05:18 | So each pair of fruits will be passed
up to it and we'll compare them saying
| | 05:22 | fruit1.length when compared to fruit2's length.
| | 05:27 | So you can see that it puts pear at
the beginning because it's the shortest
| | 05:31 | string, and banana at the end
because it's the longest string.
| | 05:34 | We could reverse the order of that if we
wanted to, just by switching fruit1 and
| | 05:38 | fruit2 or we can sort it the first
way we did it, and then just apply that
| | 05:42 | .reverse at the end.
| | 05:43 | Now there is an easier way.
| | 05:45 | If we know that we are just going to
sort it according to one simple property
| | 05:48 | like that, we can say fruits.sort by,
and then we would have just one value that
| | 05:55 | is going to be yielded up to our block
variables, and we just need one fruit,
| | 05:59 | and then we can say fruit.length. There we go.
| | 06:02 | So now we get the same effect, just by
using sort_by allows us to do it a little faster.
| | 06:08 | Now essentially what sort_by is doing
is it's saying go to the blocking get the
| | 06:12 | value I should use for a comparison.
| | 06:14 | The comparison is actually internal to sort_by.
| | 06:17 | So it's making use of the same thing.
| | 06:19 | It's just little more
convenient to do it using sort_by.
| | 06:23 | Finally, just to further illustrate
the point, let's change it from length.
| | 06:27 | Let's sort it by the reverse order.
| | 06:31 | So what that does is it says okay, go
to each one, reverse the characters, and
| | 06:36 | sort it based on the word backwards.
| | 06:38 | Now it didn't actually output the word
backwards, but banana went first, because
| | 06:42 | it ends an A, orange went second because
it ends an E, and then G. If we look at
| | 06:47 | apple, it's E and then L, which comes
after G, and pear is at the end, it's R.
| | 06:51 | So it's sorted it based on the
alphabetical order if we reversed it.
| | 06:55 | So I think you get the idea now.
| | 06:57 | The last thing I want to show you is
just that fruits for example hasn't changed.
| | 07:01 | It's in its original order still,
just like when I first defined it.
| | 07:04 | But there is a exclamation point version
just like there was for merge and collect.
| | 07:08 | So we can have the same thing.
| | 07:09 | Let's go up here to our
long example. Here we are.
| | 07:13 | We can just use our cursor and go
over, and right after Sort, put an
| | 07:17 | exclamation point, and now when we
ask for fruits, it is permanently sorted
| | 07:22 | instead of just being temporarily sorted,
in which case we would have to catch
| | 07:25 | it with a variable.
| | 07:26 | The last thing I want to show you is
that while arrays are typically what we
| | 07:29 | would sort you can sort hashes as well.
| | 07:32 | The thing is that Ruby turns a
hash into an array to do the sorting.
| | 07:36 | So let's take a look real
quick at how that would work.
| | 07:38 | I am going to put in a real simple hash
here, C is going to be 222, A is going
| | 07:42 | to be 555, D is 111, and B is 333.
| | 07:45 | So if you want a sort of hash, what
Ruby is going to first do is say hash to
| | 07:50 | array and that's what
it's going to turn it into.
| | 07:52 | It's not going to be a hash anymore.
| | 07:54 | This is very important.
| | 07:55 | So when we talk to the code block, the first
one will be this item compared with this item.
| | 08:03 | So if we just compare the items
themselves, well unless both the key and the
| | 08:07 | value are the same, which is not
possible in the hash, because the key can't be
| | 08:11 | the same, they would replace each
other, unless that's true, we have to do
| | 08:15 | something else in order to
make this a productive sort.
| | 08:18 | Let me just show you that
the hash still is the same.
| | 08:20 | So we'll have hash.sort and
then we are going to have item1.
| | 08:25 | That will be that first one, item2, oops, I
forgot my upright pipe, and the other pipe.
| | 08:32 | And then, we'll do our comparison.
| | 08:34 | Item 1 versus item 2, but we need to
look at something inside item1, and this is
| | 08:40 | the item at index 0.
| | 08:42 | We know how to work with arrays.
| | 08:45 | So the item at index 0, when compared
with the item2 at index 0, and that will
| | 08:53 | sort them by their keys A,B,C,D, or if
we asked for item1, now it sorts them
| | 09:01 | according to their values 111, 222, 333, 555.
| | 09:05 | That's one important thing you need
to remember about hashes is that they
| | 09:08 | get converted into arrays, and so in
that code block, you can't talk to it
| | 09:11 | like a hash anymore.
| | 09:12 | It doesn't have its key value pairs
anymore. Instead, it is now an array that
| | 09:17 | has 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:00 | In this movie, we're going to take a
look at inject, which is another Ruby
| | 00:03 | method that makes good use of code blocks.
| | 00:05 | Well, it may help to know
that inject is an accumulator.
| | 00:08 | So that's what it's going to do.
| | 00:09 | It's going to accumulate for us.
| | 00:11 | So when you see the word inject
immediately think accumulate, and if we're
| | 00:15 | going to accumulate values then
we're going to need a place to accumulate
| | 00:18 | them, right, a variable.
| | 00:19 | And so we'll have a block variable
that will do our accumulating for us.
| | 00:23 | And by convention, we call
that block variable, memo.
| | 00:26 | You can call it something else if you
want, but most programmers are going to
| | 00:29 | use memo and I suggest you do too,
just to remind yourself that's what it is.
| | 00:33 | That this is the accumulator
where we're accumulating our values.
| | 00:36 | I think it's also helpful before we look at
inject to look back at collect for a second.
| | 00:41 | We saw how we could have a range like
1 through 10 and use the collect method
| | 00:44 | with the block and we would apply that block
as a transformation to each one of the elements.
| | 00:49 | Well, with Inject, we're going to be
doing the same kind of thing but we're
| | 00:53 | going to be taking that value and
accumulating it each time and we're going to
| | 00:58 | be storing it in memo.
| | 01:00 | So that's going to be the difference.
| | 01:01 | So now let's take a look at inject.
| | 01:03 | So here we once again have 1 through 10,
we're going to use the inject method
| | 01:06 | and then we have our code block.
| | 01:07 | There is memo right off the bat, we've
declared memo as being the accumulator
| | 01:12 | and then the invariable is where each
one of the elements will be yielded up so
| | 01:17 | that we can use it in our block,
just like we had with collect.
| | 01:19 | So now, our block needs to tell it how
should I do this accumulation and the end
| | 01:24 | result of whatever we put in there
is what's going to be stored in memo.
| | 01:29 | So, if we just put the number 1 there,
then it doesn't matter how many elements
| | 01:33 | at the end, memo is equal to 1, because
every time it loops through, we just say oh!
| | 01:38 | 1, 1, 1, 1.
So memo is equal to 1.
| | 01:41 | Now, what I've done here in this example is
shown you a simple sum of all the numbers.
| | 01:46 | So each time it's going to go through,
it's going to take whatever value it had
| | 01:49 | previously and add the next number to
it and then store that in memo, then take
| | 01:54 | the next value and so on.
| | 01:55 | Let's walk through it just
to make sure it's really clear.
| | 01:57 | When it starts out, memo
is going to be equal to 1.
| | 01:59 | Now that's just because it takes the
first value as its initialization values.
| | 02:03 | So it will take 1 as memo and
then it will go to the second value.
| | 02:07 | When it goes to the block the first
time, memo is already 1 so then we'll say
| | 02:12 | memo equals memo plus 2, which is 3.
| | 02:15 | It'll store that in memo and
will go to the next time through.
| | 02:18 | The next element is 3.
| | 02:19 | So memo will be equal to memo plus 3 and
so on, until we accumulate all of those
| | 02:25 | values which is a sum of
all the numbers 1 through 10.
| | 02:27 | Let's start by launching an irb
session with simple-prompt and let's
| | 02:33 | create ourselves an array.
| | 02:34 | Let's just say array equals, and let's
use that splat operator, *1...10, and
| | 02:41 | we'll make a full array, 1 through 10.
| | 02:44 | Now, let's do the sum that we just saw.
| | 02:45 | Sum equals and we'll take our array
and we'll inject, declare memo and n and
| | 02:55 | then we'll say memo+n is what should
you do each time, storing the resulting
| | 03:00 | value in memo automatically . So,
the fact that the word memo is there,
| | 03:04 | this is the process that we're doing.
| | 03:06 | We are telling it use your old value memo.
| | 03:09 | The results of this will be stored in the new
memo value that will be passed to the next loop.
| | 03:13 | So here it is, the answer is 55, and
sure enough, if you take all the numbers 1
| | 03:17 | through 10 and you add
them up, you come up with 55.
| | 03:19 | Now, you may have thought it was
little peculiar that the first time through
| | 03:23 | that memo gets set to 1 automatically and
it doesn't actually apply the block to it.
| | 03:28 | It only really applies the block
the first time when it gets to 2.
| | 03:31 | That's the behavior if we don't give it
another value, but we can give it another value.
| | 03:35 | We can say array.inject and then in
parentheses here, we'll provide the starting values.
| | 03:41 | So let's say 100.
| | 03:42 | That's the initialization value of memo.
| | 03:44 | So now the first time through, memo
will be equal to 100 and the first number
| | 03:49 | it adds to will be 1.
| | 03:50 | Okay, so that will be the first iteration
that will be starting with the number 1.
| | 03:54 | Whereas before, it used the first
number as an initialization value and
| | 03:58 | the first iteration was actually with 2.
| | 04:00 | So let's just try it and you'll see now
we get 155, it starts with 100 and then
| | 04:05 | it adds them all up.
| | 04:06 | Of course, we're not limited to just addition.
| | 04:08 | Otherwise we could just call it sum.
| | 04:10 | But instead, we can do a
lot more complex things.
| | 04:12 | For example, let's say product equals
array.inject and memo n and memo times n.
| | 04:22 | So now, it will give us the product of
all of those numbers multiplied together,
| | 04:26 | 1 through 10 and just like the one
above it, we could give it a starting value.
| | 04:30 | For example, if I said, if the
starting value is 2 then now, it will be that
| | 04:35 | same number times 2 because it starts
out with the value of 2 and then does all
| | 04:39 | of its multiplication.
| | 04:40 | Now just like we're working with the
collect method, you want to be careful
| | 04:43 | about the value that gets returned here.
| | 04:45 | You want to make sure that it always is the
value that you really do want to store in memo.
| | 04:51 | Okay, so that whatever comes out of this,
the resulting return value is what you want
| | 04:56 | and if I instead said, well let's
go through it but this time, let's do the
| | 05:00 | plus n if n is not equal to 3.
| | 05:05 | So we add it but only if n is not equal to 3.
| | 05:07 | If we run that, we'll see we get an
error and the error is essentially
| | 05:11 | saying that it tried to use the plus,
addition, when we had nil and you can't
| | 05:16 | add something to nil.
| | 05:18 | Nil is not the same thing as zero.
| | 05:20 | What happened here is that when it looped
through and it got to the number 3, it said, oh!
| | 05:25 | well n is equal to 3, so I'm
not going to run this at all.
| | 05:29 | So none of this statement takes place.
| | 05:31 | And the resulting value is nil
and nil is what gets stored in memo.
| | 05:36 | That's the end result.
| | 05:37 | So, nil gets put aside and in the next
time through, it tries to add nil and the
| | 05:42 | number 4 together and it gives an error.
| | 05:43 | So just be careful about that and make
sure that the value you are returning
| | 05:47 | really is the value you intend to
store at the end of that iteration.
| | 05:52 | Let me show you another example
that frequently trips people up.
| | 05:56 | It is something that we also saw
earlier with collect which is if you do some
| | 05:59 | kind of an output in here.
| | 06:01 | So we're going to puts memo plus n.
Well we get the same kind of error because
| | 06:06 | the return value from this is nil.
| | 06:09 | Now, one way to work around this,
if we really do want to do that, we could
| | 06:13 | also use an each method.
| | 06:14 | That's probably the better way to do it,
is to do each and do a puts that way.
| | 06:18 | But if we're really trying to
accumulate, what we could do is say well that
| | 06:21 | final value ought to be memo, for example.
| | 06:24 | A semicolon, let's just put it on the same line.
| | 06:27 | So that's the one time we
can use semicolons in Ruby.
| | 06:29 | So now it does output results every
time without giving us an error, but what
| | 06:34 | it's actually doing is setting memo equal to
1 every time because it started out being 1.
| | 06:38 | So, it puts 1 plus 2 which is 3, but
then it says, "and your return value is 1"
| | 06:44 | and so it just sets memo
equal to 1 every single time.
| | 06:47 | So, again, the overall point is just to
be conscious that the result of all of
| | 06:51 | this is what's going to be
stored in memo for the next iteration.
| | 06:55 | Hence, you want to make
sure that is what you intend.
| | 06:57 | Now, let's look at some more
exotic examples that we could do.
| | 07:01 | Let's say fruits, we got apple and we'll
have a pear and let's have a banana and a plum.
| | 07:09 | So there's our fruits.
| | 07:11 | Now, right off the bat, you might think
that you can't use inject with an array
| | 07:15 | that's made of the strings like this,
but there's no reason you can't.
| | 07:18 | All we're doing is storing values
for the next round. That's all it is.
| | 07:22 | We're storing a value each time we go
through that we'll then use in the future.
| | 07:25 | So for example, let's try longest_word
equals and we'll take fruits, we'll use
| | 07:32 | inject and we'll use the do form this
time because we're going to use it on
| | 07:36 | multiple lines, fruit.
| | 07:39 | And then let's put if memo length.
| | 07:43 | So the length of whatever was stored
before is greater than the length of
| | 07:48 | whatever we are looking at now.
| | 07:51 | So if memo is greater, we want to keep
memo, but if not that means that fruit
| | 07:57 | was longer and so what we want
to save this time around is fruit.
| | 08:02 | So each time we're just saving the
string and in the end, it will tell us what
| | 08:05 | the longest word was.
| | 08:06 | So, it goes through with each one
and does a comparison and says, "ah!
| | 08:10 | This one is the best one I've got
right now" and then the next time through,
| | 08:13 | it says, "let's compare what we had last time
that was our winner with what we've got now."
| | 08:18 | Ah! That old one was actually still better.
| | 08:20 | So let's keep apple around one
more time because it beat out pear.
| | 08:24 | So then we go to the next one and this is ah!
| | 08:26 | But now, banana is longer.
| | 08:28 | Banana is longer than apple so we're
now going to store banana into memo.
| | 08:32 | And then in the final round, it compares
banana, which was stored, with the next
| | 08:36 | one which is plum and banana
is longer so it returns memo.
| | 08:40 | So, that's its final result at the end and
that's what it sets equal to the longest word.
| | 08:44 | Real quick, I'm just going to give you
another example of a place that you could
| | 08:47 | use this kind of thing
potentially in the real world.
| | 08:50 | Let's imagine that you have a website
and you have a menu bar that goes across
| | 08:54 | the top that tells all about the company, okay.
| | 08:56 | So let's say that menu bar looks
something like this, a Home, History, Products,
| | 09:01 | Services and Contact Us.
| | 09:02 | That's the string that's
going to be across there.
| | 09:04 | We could use menu.inject and let's
say that we have five characters of
| | 09:10 | margin on either side.
| | 09:11 | So there's five on the left, five on the right.
| | 09:13 | We want to find out our total width.
| | 09:15 | We could do that with memo in each item and
then we could say memo plus the item length.
| | 09:21 | And that will come back and tell us,
your total width of characters is 47 and
| | 09:28 | then we could scale that up to however
many pixels and know how wide our website
| | 09:31 | should be or something like that.
| | 09:33 | So, I think the first couple of
examples give the easy and common way that we
| | 09:37 | would use memo but I think then these
last ones show the more complex ways
| | 09:42 | that we can use it.
| | 09:43 | We don't just have to do math with it.
| | 09:45 | We can do different kinds
of comparisons and checking.
| | 09:48 | There could be all sorts of stuff going
on, but the end of the day, we just say
| | 09:52 | okay, and for the next iteration,
this is what you should keep around.
| | 09:55 | That's the important part.
| | 09:56 | That's what it does.
| | 09:57 | It's an accumulator that accumulates
values in memo and we can accumulate
| | 10:01 | whatever we want in it.
| | Collapse this transcript |
|
|
5. MethodsDefining and calling methods| 00:00 | In this chapter we're going
to talk about Ruby's methods.
| | 00:02 | We are going to start out by talking
about how we can define and call methods.
| | 00:05 | Now we've been working with methods
already, as early as when we were talking
| | 00:08 | about the string class, we had Hello.
| | 00:11 | and we put the Reverse method on it,
and that reversed all the characters.
| | 00:14 | And then we took the result to that,
and we applied another method to it,
| | 00:17 | the Capitalize method.
| | 00:18 | And we did similar things, and we
were looking at iterators and we were
| | 00:20 | looking at code blocks.
| | 00:22 | Now these methods are object methods.
| | 00:23 | They're meant to be applied to an object.
| | 00:26 | That's a little bit different than what
we'll start out with, because we haven't
| | 00:29 | learned about object classes yet, and
we'll get to that in the next chapter.
| | 00:32 | This is going be basically
standalone methods that we're talking about.
| | 00:35 | In a lot of other programming languages,
they just call it Functions, but in
| | 00:38 | Ruby we call them methods.
| | 00:40 | The way you create a method is very
simple, we have def, which is short for
| | 00:44 | define, and then the name of our
method, then we have end, at the end, and
| | 00:48 | in between def and end is the code that we
want the method to execute, when it's called.
| | 00:53 | Defining method is that easy.
| | 00:54 | Let's go to irb and create one.
| | 00:56 | So I am going to have simple-prompt
after irb, and let's try def, and we'll make
| | 01:02 | a simple welcome method, puts "
Hello World!" So there we are.
| | 01:09 | We've defined our method now.
| | 01:11 | Notice the return value of defining the
method is nil, and it didn't actually do
| | 01:15 | the code inside, right?
| | 01:16 | The puts "Hello World!" didn't happen.
| | 01:18 | That's because we've defined the
method, but its code that's sitting there
| | 01:21 | waiting for us to call it.
| | 01:23 | And the way that we call it is
just simply by giving the method name.
| | 01:26 | There is no dot notation here, dot
notation is when we are talking about object
| | 01:29 | methods, which we'll get to, and we
are just talking about standalone methods
| | 01:32 | you just call the name, and you
will see now it executed the code.
| | 01:35 | It did the puts "Hello World!".
| | 01:37 | The reason why methods are useful, the
reason we're going to want to use them is
| | 01:40 | because we can put large blocks of
complex code inside them, and then call all
| | 01:45 | of that complexity with one single name.
| | 01:47 | Now, because we are talking about
putting large blocks of complex code, it means
| | 01:51 | that irb is going to stop being quite
as useful for us as it has been, when we
| | 01:55 | are using it for the simple calculations.
| | 01:57 | So instead, we are going to move over
to the file system, and start creating
| | 02:00 | Ruby files that we can run
from the command line instead.
| | 02:03 | So I'll just quit out of that.
| | 02:05 | Let me hide irb, and now you'll notice
that on my desktop, I have got a folder
| | 02:09 | called ruby_sandbox, and that's where
I am going to be putting all this work.
| | 02:12 | So I open that up, you'll see that there is
already a file and they are called methods.rb.
| | 02:16 | We'll open it up and take a look at in a moment.
| | 02:18 | If you don't have the exercise files,
you can pause the movie and copy down what
| | 02:22 | I've got, but if you do have them, you
can find this file there and make a copy
| | 02:26 | into the ruby_sandbox. Let's take a look.
| | 02:29 | I've just put some simple method
definitions in there, I've got my
| | 02:31 | welcome definition.
| | 02:33 | I've also got add, which just adds one and one.
| | 02:36 | I've got one called longest_word,
notice the underscore between them, just
| | 02:40 | like a variable names.
| | 02:41 | This finds the longest word out of this
array of words, and it uses the inject
| | 02:46 | method that we saw from the last chapter.
| | 02:47 | Finally, I've got a method called over_five?
| | 02:50 | with the question mark at the end.
| | 02:52 | Method names can have question marks
and that can be really useful to indicate
| | 02:56 | to yourself when you're using it that
it is used for a test, that it's going to
| | 03:00 | test some value, and either return the
results of this test or maybe a boolean.
| | 03:04 | Now in this case I am not returning just
true or false, I am actually returning text.
| | 03:08 | And now I am actually going to put that
test, either over_five? or Not over 5.
| | 03:12 | Now we have our methods.
| | 03:14 | So let's save this file, and let's go
back to our command line, and what we want
| | 03:18 | to do here is navigate to wherever that file is.
| | 03:21 | So cd and for me that's going to be
inside desktop, inside ruby_sandbox, and
| | 03:26 | that's where I am going
to find that methods file.
| | 03:28 | And then just ruby methods.
rb will execute that file.
| | 03:33 | It may not look like it
did anything, but it did.
| | 03:36 | It read in all four of those methods, it
defined them, but then they didn't do anything.
| | 03:40 | The same way up here we just did our
definition of welcome, but then nothing
| | 03:43 | happened until we actually called it.
| | 03:45 | Now we need to call those methods.
| | 03:48 | Well, there's a couple of ways we can do
that, and I want to show you both of them.
| | 03:51 | The first is that we can go back into
irb, and we can use require, and require,
| | 03:56 | and then what the name of the file is
that we want to require in quotes and you
| | 04:00 | can also provide more of a path
information if you need to help if find where
| | 04:04 | that file is, but if you are already in the
same folder, you should just find it right there.
| | 04:08 | So responded with true, which means
that it was able to find the file, and it
| | 04:12 | did read it in, and process it, right?
| | 04:14 | So all the Ruby code that
was in there was executed.
| | 04:17 | So in this case, it made
four definitions for us.
| | 04:19 | So now we can just say
welcome, and now we can call it.
| | 04:23 | So we have access to all
of our methods, over_five?
| | 04:27 | and Not over 5 is what it returns.
| | 04:29 | That's the first way.
| | 04:30 | The second way is that we can actually
open up that file, and in the file we
| | 04:35 | can now say welcome.
| | 04:37 | Now when we run the file, again, I am
just from the regular command line not in
| | 04:40 | irb, ruby methods.rb now it outputs
those results to our command line, not to
| | 04:47 | irb to our command line.
| | 04:48 | It will output to either place.
| | 04:50 | Now of course, if we go back in to irb,
when we do this require now, it's going
| | 04:55 | to do that output, we'll still be able
to have some interactivity afterwards,
| | 04:59 | but it will do the same
thing just inside irb first.
| | 05:04 | So I want you to feel comfortable being
able to switch back and forth if we need to.
| | 05:07 | The technique of going into irb is
useful, if you want to continue to interact
| | 05:11 | with it, after it's done.
| | 05:13 | If we just want to run the script and
then be done with it, then we can just
| | 05:16 | simply run it from the command line.
| | 05:18 | So let's switch back to methods now, and
let's go ahead and call our other ones.
| | 05:21 | We have add, we have longest_word,
and we over_five? There we are.
| | 05:28 | So once again, I'll just run Ruby
methods, and you'll see that it does all four
| | 05:32 | of those successfully.
| | 05:33 | One last point I want to make is that we do
have to define our methods before we call them.
| | 05:37 | So I have just added a little note here
that's probably commonsense, but it does
| | 05:41 | read this page in order, and so
things get processed in order.
| | 05:45 | For example, if we were to put
welcome up here at the top before it's been
| | 05:49 | defined, we'll Save it.
| | 05:50 | We'll go back and run it.
| | 05:52 | You'll see it comes back and says, "oops!
| | 05:53 | I don't recognize that, I
don't know what to do with that."
| | 05:56 | So we do have to do the definition first.
| | Collapse this transcript |
| Variable scope in methods| 00:00 | Now that we have seen how to
define Ruby methods, I want to take this
| | 00:02 | opportunity to take a look at variable scope.
| | 00:05 | We first talked about variable scope
back when we introduced variables, and at
| | 00:08 | the time I told you that we really
wouldn't be able to go into it in any kind of
| | 00:11 | depth until we had some more complex
Ruby structures that we could look at and
| | 00:15 | see how variables interacted in those context.
| | 00:18 | We revisited the subject again when
we got to blocks and now that we have
| | 00:22 | methods, we can see how variable
scope applies to methods as well.
| | 00:26 | In my ruby_sandbox, I have now got
another file called method_scopes.
| | 00:29 | Its basically the same file that we
were working with, I just saved a different
| | 00:32 | copy of it, so that I
could keep the work separate.
| | 00:34 | I have also removed all the
comments that we had made.
| | 00:36 | You will notice in our method
definitions we are using local variables in a few
| | 00:40 | places, words, longest_word, and value.
| | 00:44 | We have also got block variables,
word and memo that we are using.
| | 00:48 | We have already seen how block variables work.
| | 00:50 | I want to focus on the local variables.
| | 00:52 | Now, the reason why they are called
local variables is because their scope
| | 00:56 | is local to the structure that they are in,
and methods are exactly that kind of structure.
| | 01:02 | So value = 3 only has scope
inside the method over_five.
| | 01:08 | Now, when I say it only has scope, that
means that it is assigned inside there.
| | 01:12 | It can be used inside there, and when
the method is over, that variable will be
| | 01:16 | discarded and can't be
used outside of the method.
| | 01:19 | We can see that if we go down here
below our method calls and we just do puts
| | 01:23 | value, and then we will Save our file.
| | 01:26 | Let's go back into our command line,
notice that I am already inside my
| | 01:30 | ruby_sandbox, and from there I
will run my new file method_scopes.rb.
| | 01:35 | So it ran our code successfully.
| | 01:37 | We got all the results from
the methods that we would expect.
| | 01:40 | But then when we got to outputting
the value, you will notice that we got
| | 01:43 | undefined local variable.
| | 01:45 | That's because value has not been set
inside this scope, the global scope of
| | 01:51 | this file, it was only set
inside the scope of the method.
| | 01:55 | The same thing is true if we were to
set a value, let's say, at the very top of
| | 01:58 | the file, value = 7, so now we will Save that.
| | 02:04 | If we run it again, now this time we didn't
get the error because value was set, value is 7.
| | 02:11 | It didn't change it when we ran our method.
| | 02:14 | Either defining it or
calling it did not change it.
| | 02:16 | Completely separate, and it
still says it's not over_five.
| | 02:20 | It didn't use 7 as a value,
and it didn't change what we had.
| | 02:23 | They are two separate variables, value and
value, because they have two separate scopes.
| | 02:29 | The same thing would be true if we
tried to output the value of words.
| | 02:32 | However, longest_word is going to be a
little bit different. Can you guess why?
| | 02:36 | Let's try just doing puts longest_word.
| | 02:41 |
| | 02:41 | We will save that file.
| | 02:42 | We will go back to our command line and
let's run it one more time, and notice
| | 02:47 | what we got this time.
| | 02:48 | We got banana and then we got banana again.
| | 02:52 | Now, you might be thinking that it
actually output banana from here. It didn't.
| | 02:57 | What it's doing is it's putting the method,
longest_word, that's what it's putting.
| | 03:02 | That's why we get this sort of strange
nil down here, at the very bottom, is
| | 03:06 | because that's actually the
result of this value that comes back.
| | 03:10 | It's putting the longest_word here.
| | 03:13 | That's when we see the word banana the
second time, because we have called the
| | 03:16 | method, and the return
value from this puts is nil.
| | 03:20 | We saw that earlier in irb.
| | 03:22 | So therefore it's now outputting nil,
and that's why we get that other nil there.
| | 03:25 | So our variable name and our method
name are the same, and that's where we are
| | 03:31 | getting this confusion.
| | 03:32 | So that brings up the point that you
want to be careful when you name your
| | 03:35 | methods to make sure that it's not
confusing and that Ruby can always tell
| | 03:39 | which one you mean.
| | 03:40 | Now in reality, once we start programming
with Ruby, it's really not that often a problem.
| | 03:44 | I just want you to be aware of it,
that your method names and your local
| | 03:48 | variables are going to look the same,
and so you want to make sure that it's
| | 03:51 | always clear which one is which.
| | 03:53 | Now, what about the case where we do
want to be able to bring in something
| | 03:57 | from outside the scope?
| | 03:58 | I am going to go ahead and just
comment this puts longest_word out for now.
| | 04:02 | So let's say, for example, we wanted to
have a word list that was defined before
| | 04:07 | we ran it, and we wanted to
make use of it inside there.
| | 04:10 | There are a couple of ways that we can do it.
| | 04:12 | One is to have a variable whose scope
does stretch inside there, and an instance
| | 04:17 | variable is that kind of variable.
| | 04:19 | So we put the at symbol in front
of it, now it does run successfully.
| | 04:23 | Let's go ahead and run it one more
time to see everything worked out just
| | 04:26 | like we would expect.
| | 04:28 | That's because this array is
available inside longest_word.
| | 04:33 | In fact, we don't even have to
have it available before we define it.
| | 04:36 | It just has to be
available before we run it, right?
| | 04:39 | It has to be available down here.
| | 04:40 | Let's take a look at the variable types again.
| | 04:43 | You recall that we had five variable types:
| | 04:45 | Global, Class, Instance, Local, and Block.
| | 04:48 | When we are working with methods, the
things that will have scope inside the
| | 04:51 | method are going to be
Global, Class, and Instance.
| | 04:54 | We can use any one of those, and it will
still be available to us inside that method.
| | 04:59 | Local and Block are going to have scope
that's limited and does not go into the method.
| | 05:04 | We don't have it available to us
once we are inside the method scope.
| | 05:08 | Now, there are times when it's
perfectly legitimate for us to do it this way,
| | 05:12 | to have a variable that's set outside of a
method and then use it inside the method.
| | 05:18 | We will especially be using that when
we start looking at classes, but most
| | 05:21 | of the time you want to use this very sparingly,
because let's say that words had not been set.
| | 05:26 | Well now, longest_word is expecting the
we have set that, and if we forget to do
| | 05:30 | it, then our method no longer works.
| | 05:32 | It becomes fragile and it breaks.
| | 05:35 | A much better way would be for us to
pass in the variable that we want to use at
| | 05:40 | the time that we call the method,
and we do that with arguments.
| | 05:43 | We can see how to do that next.
| | Collapse this transcript |
| Arguments| 00:00 | In this movie I want to talk about arguments.
| | 00:02 | When I say arguments, I don't mean
the disagreement between two people.
| | 00:06 | In programming, arguments are going to
be a comma-separated list of values that
| | 00:10 | we pass into our methods.
| | 00:12 | It's a way that we can get around the
problem that we saw in the last movie of
| | 00:15 | variable scope, because now it doesn't
matter what the scope is, when we call
| | 00:19 | the method, we pass in the
values that it's going need.
| | 00:22 | We don't have to make sure that
they have all already been set.
| | 00:24 | We pass them in at the time that we call
them, and that's going to be arguments.
| | 00:27 | You will also sometimes see arguments
abbreviated as just args, so if you see
| | 00:33 | that, that's what it means.
| | 00:34 | It's just short for arguments.
| | 00:37 | In my ruby_sandbox, you will see that
I have a file already called arguments.
| | 00:40 | It's basically the same code that we
have been working with, but I have added
| | 00:43 | a comment to the top, noting that methods
with arguments typically use parentheses.
| | 00:48 | Methods without arguments typically do not.
| | 00:51 | But it's completely optional as to
whether we use them in both cases.
| | 00:54 | So that's just sort of the standard.
| | 00:56 | If we have something that's just
welcome and we don't need arguments, we don't
| | 00:58 | put the parenthesis, but we could, we
would just put parenthesis after it.
| | 01:02 | If it was going to have arguments, then we
probably would put them, but we don't have to.
| | 01:07 | In order to make arguments work, we are
going to need to have a local variable
| | 01:10 | that's going to catch those values
as they are passed in to our method.
| | 01:15 | So for example, name.
| | 01:17 | Now we can make use of that local
variable inside our method, and it has the
| | 01:22 | same scope as we had down
here when we defined value.
| | 01:25 | Just to show you what I was talking
about with parenthesis, we could just leave
| | 01:29 | off the parenthesis as well and that would work.
| | 01:32 | Typically you don't see that.
| | 01:33 | You usually do see the parenthesis.
| | 01:35 | Now our welcome method is expecting to
receive one argument which it will assign to name.
| | 01:42 | Let's try it out.
| | 01:42 | We will go over to our command line,
notice that I am already inside my ruby_sandbox.
| | 01:48 | We will type ruby arguments.rb.
| | 01:52 | Notice that I get an error.
| | 01:53 | Welcome gave me an error, wrong
number of arguments (0 for 1).
| | 01:58 | That's the important part here.
| | 02:00 | I sent it zero arguments and it was
expecting one, and that's the important
| | 02:05 | point about arguments.
| | 02:06 | Once we have defined an argument
here, it's expecting to receive it.
| | 02:09 | We are essentially saying hey, I
need this before I can keep going.
| | 02:13 | So when we call welcome down here, we
now have to put in a value, like Mary.
| | 02:19 | Now it will pass in the string Mary
as a value that will be received by the
| | 02:24 | local variable name and then
used inside. Let's try it.
| | 02:29 | ruby arguments, Hello Mary!
| | 02:31 | And the nice thing about that is now it's
reusable, we could have Hello Mary! and Hello Larry!
| | 02:37 | We can call it twice, and the only
thing that we are doing different is we are
| | 02:43 | sending a different value inside for it to use.
| | 02:46 | Before we go on, let me also just show
you that when you call these values as
| | 02:49 | well, we don't have to put the parenthesis.
| | 02:51 | We could have Hello Mary! Hello Fred!
| | 02:55 | There we are.
| | 02:56 | I left off the parenthesis around it.
| | 02:57 | It's still an argument that's being
passed in, ruby arguments, Hello Fred!
| | 03:02 | Now up here, typically we do put the
parenthesis with arguments, down here when
| | 03:07 | we are calling it, it's
really a matter of personal style.
| | 03:10 | Some Ruby developers do it one way, some do
it the other, there's no right or wrong answer.
| | 03:14 | It's really a matter of
your personal preference.
| | 03:16 | Throughout the tutorial, I am going to
put them in there, because I think it
| | 03:18 | makes it clearer for beginners especially to
see where the argument list starts and stops.
| | 03:23 | We can also add arguments
to our add method up here.
| | 03:26 | We will put our parenthesis and we
can put multiple arguments, n1, n2.
| | 03:31 | Remember it's a comma-separated list of values.
| | 03:33 | So the commas will know where to break
each of those values, and then we can
| | 03:37 | make use of those, n1 and n2, and we
will need to pass those in down here.
| | 03:42 | So let's say 2, 2, not 2+2, 2, 2,
those are each of the arguments that are
| | 03:49 | being passed into it.
| | 03:50 | Let's take a look at longest_word.
| | 03:52 | We could have, for example,
the word list being sent in.
| | 03:55 | This is a lot better than the other
solution we were looking at earlier.
| | 03:58 | Remember we were doing something like
this, where we had the instance variable
| | 04:01 | that was being used.
| | 04:02 | Well now, we can just take our words, we
will just come down here before we call
| | 04:07 | it, and let's actually rename them to fruits.
| | 04:11 | We can pass in fruits as an array.
| | 04:14 | It will then become the local
variable words once we are inside.
| | 04:20 | It might have been fruits.
| | 04:21 | It might have been cars.
| | 04:23 | It might have been dogs. It doesn't matter.
| | 04:25 | Once we pass it in, it gets assigned to
words, and we work with it then as the
| | 04:29 | local variable word.
| | 04:31 | Let's change over_five to just be
value, and now we just take this out and
| | 04:36 | over_five, we can pass in a value.
| | 04:38 | Let's pass in 8 this time.
| | 04:39 | I will just put some spaces in here so
we can separate these out and see all
| | 04:43 | the different ones. Save it.
| | 04:45 | Let's go back and run it one more time,
and you will see that everything works,
| | 04:49 | all my arguments get passed in successfully.
| | 04:52 | Now our methods are much more usable
because now they are flexible and we can
| | 04:55 | use them in lots of different contexts,
and we don't have to go to the trouble
| | 04:59 | of setting instance
variables or anything like that.
| | 05:01 | We can just, at the time we call it, we can
pass in the values that we want it to use.
| | 05:05 | So, for example, over_five becomes
a lot more useful now that we can do
| | 05:09 | something like 112/18.
| | 05:12 | I don't know off the top of my head
whether that's going to be over_five or
| | 05:15 | not, but we can run our method and find out
that, yes, it is in fact going to be over_five.
| | 05:20 | As you can see, arguments are what give the
real power and flexibility to our methods.
| | Collapse this transcript |
| Argument default values| 00:00 | In the last movie we saw how if we
didn't send the same number of arguments to
| | 00:03 | our method as it was
expecting, that we got an error.
| | 00:06 | In this movie we are going to see
how we can use argument default values
| | 00:10 | to avoid those errors.
| | 00:12 | You will see that I have a new file on
my ruby_sandbox, its argument_defaults,
| | 00:15 | and I will open it up.
| | 00:16 | It's basically the same file that we have
been working with, just a little bit cleaned up.
| | 00:19 | The case that I want us to look at is
how we can set a default value so that,
| | 00:22 | for example, if we called welcome, and
we just called it by itself and we did
| | 00:27 | not send anything, that there would
be a default behavior that would happen
| | 00:30 | instead of giving us the error.
| | 00:33 | The way we do that is we just go ahead
and make an assignment to this variable
| | 00:36 | inside the argument list.
| | 00:38 | So Hello World, for example.
| | 00:40 | Now when we call it, we don't get an
error anymore, because even though we
| | 00:44 | didn't send an argument, it was
satisfied because it said, ah, my argument did
| | 00:48 | get a value in the end, not one you
sent to me, but one that I set myself.
| | 00:53 | So it's the equal sign right after it.
| | 00:56 | If we have multiple arguments, you just
assign them each, like =0 and then for
| | 00:59 | this one, =0.Let's go
ahead and just try that out.
| | 01:02 | Let's just say add, and for add,
let's go ahead and submit 3.
| | 01:06 | We will just put in one argument.
| | 01:08 | So we are going to add 3.
| | 01:09 | It doesn't really make sense,
but that's what we are going to do.
| | 01:11 | We will go into our Terminal.
| | 01:13 | Notice that I am already inside
ruby_sandbox, and I will just run
| | 01:17 | ruby argument_defaults.
| | 01:20 | So there it wrote Hello Mary!
| | 01:22 | Then we get Hello World!, the default behavior.
| | 01:25 | We added 2 and 2 and we got 4. We added 3.
| | 01:28 | It just came back with 3.
| | 01:29 | Because we sent 1 and it got used here as n1,
and then n2 got assigned the value of 0.
| | 01:38 | Obviously, the order of our
arguments is going to be important.
| | 01:41 | It has to know which one of our values to
assign to which one of these slots up here.
| | 01:45 | So, for example, 3 would never end up being n2.
| | 01:49 | Its always going to get assigned
to n1, because it's the first value.
| | 01:53 | If I put something else in front of it,
nil, let's say, then nil would get
| | 01:56 | assigned to n1, and 3 would get assigned to n2.
| | 01:59 | So the order does matter.
| | 02:01 | You want to be careful about that.
| | 02:02 | Therefore, you will want to make
sure that you put all of your required
| | 02:05 | arguments up at the front.
| | 02:07 | You could do n1 and then n2.
| | 02:09 | So n2 is optional now, n1 is required.
| | 02:12 | If I did it the other way around,
this isn't really that useful.
| | 02:16 | It's going to give me an
error unless I provide both.
| | 02:19 | There's no circumstance
where I can just provide 1 to it.
| | 02:22 | If I just give this, add 3, it would say oh,
n1 is equal to add 3, but n2 gives me an error.
| | 02:28 | It's not really that flexible.
| | 02:29 | So you just want to make sure that if
you have some that are required and some
| | 02:33 | that are not, the required ones are the
first ones there, so that then as you go
| | 02:37 | down the list, the
optional things come later on.
| | 02:40 | Now, we have already seen how we can put a
string and an integer as being the variables.
| | 02:45 | We can also put in arrays as a default value.
| | 02:47 | So there's just an empty array,
two square brackets side-by-side.
| | 02:51 | That's going to say look, if you don't
get an array, then set yourself to an
| | 02:54 | empty array, which a lot of times will
keep your method from blowing up on you,
| | 02:58 | because it will then have a default value.
| | 02:59 | So if you are doing like each, for
example, doing each on an empty array will
| | 03:04 | just not do anything.
| | 03:06 | But having nothing assigned to it
will give you an error saying, "oops, you
| | 03:10 | didn't send in the value, I am not
very happy with you," kind of thing.
| | 03:14 | So let's try that down here.
| | 03:15 | Let's just try longest_
word and see what we get back.
| | 03:19 | Then same thing with over_five.
| | 03:21 | Let's try setting it to nil.
| | 03:22 | We are going to say if you don't get a
value, then don't object, don't raise an
| | 03:27 | error, just set value equal to nothing.
| | 03:30 | Don't pass an error, just keep on going,
because I am okay with the fact that I
| | 03:33 | might not have gotten value.
| | 03:36 | Let's just do over_five by
itself and see what we get now.
| | 03:40 | So let's try all this out.
| | 03:42 | We will come back over here, and defaults.
| | 03:44 | Now, notice that over_five still
raised an error, but the error was
| | 03:47 | different this time.
| | 03:49 | The error this time was,
undefined method > for the NilClass.
| | 03:54 | So it basically said, well, I don't know
how to handle that with nil, if we were
| | 03:58 | to instead just put a to_i on it to
make sure that it changes it into an
| | 04:02 | integer, then we can get it to pass.
| | 04:05 | So now it goes through and
it says, "ah, I got nil."
| | 04:08 | I am going to convert nil to an integer,
which is going to be 0, and therefore
| | 04:13 | it will say, "ah, 0 is not greater than 5."
| | 04:16 | So we got an error, but the
error was not an argument error.
| | 04:19 | When you are programming and you are
defining your methods, it's always a good
| | 04:22 | idea to stop and take a second when you
are making your argument list, and think
| | 04:26 | about what really is required
for this method to do its job.
| | 04:30 | For example, over_five, having nil
really doesn't make a lot of sense.
| | 04:33 | So we might say you know what, if you
are going to use over_five, you have
| | 04:36 | to send me a value.
| | 04:38 | Now, we still might want to do this to_
i in case we were to send a string or
| | 04:40 | something like that.
| | 04:41 | It's not a bad idea.
| | 04:42 | But if we leave it out, then we are
basically saying you must send me a value.
| | 04:46 | If we put in something like 0 or nil,
then what we are saying essentially is
| | 04:51 | it's okay if you don't, I
will handle it, I will live.
| | 04:55 | So as you are making your argument list,
always stop and think about where your
| | 04:58 | default values ought to be.
| | Collapse this transcript |
| Return value| 00:00 | In last movie, we saw how we could use
arguments to get values into our methods
| | 00:04 | so that we could use them.
| | 00:05 | What about getting values
back out of the methods?
| | 00:08 | For that, we need to take a
look at the method Return Value.
| | 00:11 | In my ruby_sandbox, you'll see I have
a new file now called return_value.rb.
| | 00:15 | If we open it up, you'll see this is
basically the same file we've been working
| | 00:17 | with, just pared down a little bit.
| | 00:19 | Now we've already been working with
return values without really knowing it.
| | 00:22 | Now, we have already seen return
values when we were working in irb.
| | 00:25 | Let's go back and just open up an
irb session to remind ourselves.
| | 00:29 | I'll just open one without simple-prompt.
| | 00:31 | If we have 1+1, we're not doing a puts, right?
| | 00:35 | We're getting the return value of 2.
| | 00:37 | If I do puts 1 +1, then we are
outputting 2, and our return value is nil.
| | 00:43 | And we talked about that puts
always has return value of nil.
| | 00:46 | So that was true in irb.
| | 00:48 | It's also true back here
in our method definitions.
| | 00:51 | So when we call welcome, it runs puts,
which outputs what we asked it to, and
| | 00:58 | then there's a return value for it.
| | 01:00 | Now, if there is another statement then
that return value just gets ignored, and
| | 01:04 | we keep going with everything else.
| | 01:06 | But what happens at the end of the
method is that the return value for the whole
| | 01:10 | method is whatever the last thing was.
| | 01:13 | So in this case, when we were doing a puts,
the return value is nil, we can see that.
| | 01:17 | Let's go down here and let's say
returned_value = welcome("John") and then
| | 01:26 | puts returned_value.
| | 01:29 | So now we can actually see
that value. Let's save it.
| | 01:31 | Notice that I'm already in my ruby_
sandbox here, and I'll just run ruby and
| | 01:35 | then return_value.rb. So here we are.
| | 01:38 | It runs the Hello John!
| | 01:40 | that's when it calls the method, because it's
still calling it here, still calls the method.
| | 01:45 | But then we are catching the value, and
we are putting it again, and that's the
| | 01:49 | nil that we're seeing here.
| | 01:51 | So they all have a return value automatically.
| | 01:54 | If we put 1+1 at the end, and
save that, now let's run it again.
| | 01:59 | Now, instead of nil we get 2.
| | 02:02 | So whatever the last value is inside
the function is what gets returned by
| | 02:06 | default, and is the exact same thing
as if we said return, return this value.
| | 02:11 | So that is the way we're very explicit about
it and say this is what I want you to return.
| | 02:16 | And return not only returns a
value, it returns from the method.
| | 02:21 | So it exits the method at same time.
| | 02:24 | So if, for example, we did 2+2,
our code will never get there.
| | 02:28 | It will never do the 2+2, because as
it's executing, it will do our output, then
| | 02:34 | it will come and do 1+1 and figure out it's 2.
| | 02:36 | It will return that value to us so that
we can catch it and work with it and it
| | 02:41 | will just stop right there.
| | 02:43 | Let's try it, and you will see that we
get the exact same thing back, we did not
| | 02:47 | get 4 as our return value.
| | 02:49 | So that's the second point.
| | 02:50 | So the first point that I made is that all
methods have a return value, even the default one.
| | 02:55 | So there is always one,
even if we don't catch it.
| | 02:57 | So in the case of welcome ("Mary
") here, we just won't catching and
| | 03:00 | doing anything with it.
| | 03:01 | The second point is if we're explicit
about it and we say return, and then we
| | 03:05 | return from the method and we are done.
| | 03:07 | Now most of the time what we want to
return is the result of the processing
| | 03:11 | that the method does.
| | 03:12 | So for example, I'll take out the 1+1, and
now we'll just do return "Hello #{name}!.
| | 03:16 | So it has the same effect, 2+2 will
never get executed, but the return value
| | 03:21 | will be the result of
whatever welcome method did.
| | 03:24 | It's processing and it did.
| | 03:26 | In this case it just made a string for us.
| | 03:28 | Now, let's just save this, run it again,
notice that we don't get Hello Mary! anymore.
| | 03:34 | We just get Hello John!,
because calling it here did nothing.
| | 03:37 | All it did was to generate the string,
return the value, and then it got thrown
| | 03:41 | away, because we didn't
catch that returned value.
| | 03:44 | In the case of welcome John, we did.
| | 03:46 | Now it's a little bit up to you as
to whether you put the puts statement
| | 03:49 | inside your method or outside the
method, and it really depends on what the
| | 03:53 | method is meant to do.
| | 03:54 | If the purpose of the method is to do some
output, then it makes sense to put it in there.
| | 04:00 | But otherwise it might make more sense
to put it outside, and that way we can
| | 04:04 | put it when we want to put it,
like we did here when we did puts
| | 04:07 | returned_value, or we could not, like
we just assigned it to returned_value, we
| | 04:12 | could to do something with it.
| | 04:13 | Let's say for example here with longest_word,
return the longest_word at the end of it.
| | 04:18 | So now instead of having the
longest_word, let's puts the
| | 04:23 | longest_word (fruits).length.
| | 04:25 | We won't get banana anymore.
| | 04:27 | Instead now, we'll get the length of that word.
| | 04:31 | We don't care what the word was,
we want to know how long it was.
| | 04:33 | It's 6, and maybe we're going
to use that for some purpose.
| | 04:36 | So not having the puts inside
the method a lot of times gives us
| | 04:40 | greater flexibility.
| | 04:41 | Doesn't mean you have to.
| | 04:42 | It's perfectly valid to have
a method that it does output.
| | 04:46 | Now so far, the return that we've been
doing has been at the end, where we were
| | 04:49 | basically saying well, return this
after we are done all the processing.
| | 04:53 | But we don't have to, in fact that's
the real power of return, is that it works
| | 04:56 | well with if statements.
| | 04:58 | So for example, here I have said
return "Exactly 5", if the value is 5.
| | 05:03 | Don't go any further.
| | 05:04 | We're just going to call it done, and if
not then do this additional process, in
| | 05:08 | which case I have another if else statement.
| | 05:10 | Now obviously you could have
written this all as one statement.
| | 05:12 | But I wanted to show you the way that
we could do return if, because this is a
| | 05:16 | common Ruby idiom that will do
return something if this is true.
| | 05:20 | Exit the method right away
if certain conditions are met.
| | 05:23 | And then if we want this to work, of
course, we'll need to do, puts over_five or
| | 05:28 | else catch that string and
do something else with it.
| | 05:30 | So frequently return is used not just
at the end of the method, but at various
| | 05:34 | points within the method.
| | 05:36 | Now, the last and perhaps most
important point I want to make about a return
| | 05:40 | value is that it's singular.
| | 05:42 | There is only one return value that comes back.
| | 05:46 | So let's rewrite our add method so that
we would like to return two values from it.
| | 05:50 | Let's say add_and_subtract, and we
need a method that will do both for us.
| | 05:54 | It's going to take n1, and figure out
what their addition is, but it's also
| | 05:59 | going to do subtraction, say n1-n2.
| | 06:03 | How can we return both of those values back?
| | 06:06 | When we have multiple values to return, the
way to do it is to put them in a single object.
| | 06:12 | In this case an array.
| | 06:13 | So add and subtract.
| | 06:15 | Now that is one object, its one
return value, but inside there are other
| | 06:21 | multiple values, and
that's what you get around it.
| | 06:23 | So we can only return one object from a method.
| | 06:27 | But that object could have
multiple objects inside of it.
| | 06:31 | It could be an array.
| | 06:31 | It could be a hash.
| | 06:32 | It could be some other more complex
object that contains lots of other stuff.
| | 06:37 | Frequently, you'll see the Ruby
developers just leave off these are square braces.
| | 06:41 | So this will just be return add, sub.
| | 06:43 | It's still returning an
array. That's what it is.
| | 06:46 | Those square brackets are just optional in
this case, so we don't actually have to have them.
| | 06:49 | But it is still an array and when we get the
value back, we'll need to treat it as an array.
| | 06:54 | For example let's do now add_and_
subtract, and let's say result = so we'll need
| | 07:02 | to puts result and the 1 item
and puts result and the 2 item.
| | 07:11 | So those are going to be
the two items in our array.
| | 07:13 | Let's just try that out.
| | 07:15 | Ruby return_value.rb, and here
we are, we get our value 4 and 0.
| | 07:19 | So, 2+2 is 4, 2-2 is 0.
| | 07:22 | Another neat trick that you can
use is you can do double assignment.
| | 07:26 | So we could say for example, add, sub =
and then let's do, add_and_subtract and
| | 07:33 | we could do something like 8 and 3.
| | 07:37 | Add, sub is actually an array as well,
just with those square braces missing.
| | 07:42 | But it does the same thing.
| | 07:43 | It does double assignment now.
| | 07:44 | So now when an array comes back, the
first value of the array goes into the
| | 07:48 | first one, and the second
one goes into the second one.
| | 07:51 | And that's a nice,
convenient shorthand to know about.
| | 07:53 | Otherwise you get little bit confused
when you say wait a minute add, sub =,
| | 07:57 | how is that possible?
| | 07:58 | Well that's what it means.
| | 07:59 | It means that this is returning two
values back and we are catching both of them
| | 08:03 | into this array of variable assignments.
| | 08:05 | So just to recap those points we've
seen about returned values, methods already
| | 08:10 | have a default return value, and it
will be the last operation's return value.
| | 08:15 | We can explicitly use return, and it will
both return the value and exit the method.
| | 08:19 | I also suggested to you that
returning a value and using puts outside of a
| | 08:24 | method can be a lot more flexible than
if you were to just simply do the output
| | 08:27 | from inside the method.
| | 08:29 | And we saw how return is especially
useful with conditional statements, and that
| | 08:32 | methods could only return one object.
| | 08:35 | You will want to use an array if
you need to return more than that.
| | Collapse this transcript |
| Operators are also methods| 00:00 | You'll be very surprised and quite
possibly amused to discover how prevalent
| | 00:05 | methods are in Ruby, and
you didn't even know it.
| | 00:08 | Common operators in Ruby are methods too.
| | 00:11 | When I'm talking about operators, I'm
talking about things like Plus. Plus is a method.
| | 00:16 | Now in most other languages, you
would just say it's an operator.
| | 00:18 | It's just very simple, 8+2,
just like on a calculator.
| | 00:21 | Now in Ruby, it's actually a method.
| | 00:24 | It's the plus method that's being
applied to the integer 8 and the
| | 00:28 | first argument is 2.
| | 00:30 | So the name of our method is that + there.
| | 00:33 | Instead of having it be a word in
English that we'd recognize, it's just the +.
| | 00:37 | Both of these will work if you
go in the IRB and try it out.
| | 00:40 | Now we've already seen how the
parenthesis around the argument list is optional.
| | 00:45 | We saw that back when we
were talking about arguments.
| | 00:47 | But there is another change that's
happening where Ruby is allowing us to
| | 00:51 | just put + instead of having to put
dot plus, and that's something that's
| | 00:56 | happening internally in Ruby to make
it easier for us to use, so we don't
| | 00:59 | have to do it the cumbersome way.
| | 01:01 | Instead, we can do it a slightly
sweeter way, and that's why we call it
| | 01:04 | syntactic sugar, because it's made
the language a little sweeter for us.
| | 01:09 | The syntax of the language is a little
sweeter, because it's much easier for
| | 01:13 | us to write expressions like 8-2, 8*2,
8/2 and 82, then it is to write the
| | 01:20 | method names for them, eight dot minus and
then parenthesis, whatever argument is, and so on.
| | 01:27 | But the column on the right is
absolutely what's going on in Ruby when you type
| | 01:31 | what's in the column on the left,
and both of these will work.
| | 01:33 | We'll try it out in a moment to
actually prove to you that it does work.
| | 01:37 | But let me show you a few more.
| | 01:38 | Let's say that we have a simple array, and to
that array we're going to append 4 to the array.
| | 01:43 | Then we're going to ask for what's at
index number 2 to be brought back out of
| | 01:46 | the array, and then we'll set the
value of what's at index 2 with the string
| | 01:52 | X. These are also all methods that look
like operators, but they're actually methods.
| | 01:58 | The first one is pretty
similar to what we saw before.
| | 02:00 | It's just the .<<, and then the
argument that's being passed in.
| | 02:05 | Again, syntactic sugar
makes it nicer and easier.
| | 02:08 | The second one might not be
as obvious how it's working.
| | 02:11 | The name of the method is actually
square bracket, square bracket.
| | 02:15 | That's the name, and then the argument
is what's inside those square brackets.
| | 02:19 | Ruby just uses syntactic
sugar to rearrange things a bit.
| | 02:22 | The 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:28 | So the method name being applied is square bracket,
square bracket =, and then the first argument is the
| | 02:33 | index and the second argument is the
value that should be put into that index.
| | 02:37 | Thankfully, we don't have to ever
write it the way it is on the right-hand
| | 02:41 | side of the screen.
| | 02:42 | We get to use syntactic sugar and write it
the way it is on the left side of the screen.
| | 02:45 | But here's the reason why it's
important to understand this.
| | 02:49 | You can name your methods
with these kinds of symbols.
| | 02:53 | So if you have something like you have a
classroom and you want to put a student
| | 02:57 | in the classroom, you can write a <<,
append method of your own that will put
| | 03:03 | the student in the classroom, or if
you have a long string, let's say it's a
| | 03:06 | page of text, and you want to break it
up into thirds, you could use the divisor
| | 03:10 | method, and use the slash
that we'd use for dividing.
| | 03:13 | It wouldn't mean to divide in the
normal sense of dividing, it would mean, take
| | 03:17 | this page and divide it up.
| | 03:19 | So keep that in mind when you're
naming your methods that you can make use of
| | 03:23 | the syntactic sugar for yourself.
| | 03:25 | Now that we understand that these are
methods being applied to objects, we can
| | 03:29 | revisit something we saw earlier, which
is that hello, the string, multiplied by
| | 03:34 | 5 gives a different result than 5
multiplied by the string, hello.
| | 03:39 | The first time we'll just get hello five
times, the second time we'll get an error.
| | 03:44 | The reason why is because the first is
taking a string and using its multiply
| | 03:48 | method on it with the argument 5,
which does have a valid result.
| | 03:52 | The second is something different.
| | 03:54 | It's an integer that is using the
multiplication method, which integers when
| | 03:58 | multiplied by something, and we
know what they'd do, right, 5x2 is 10.
| | 04:03 | Well, when you pass it a
string, it says, "wait a minute.
| | 04:06 | I was expecting it an integer.
| | 04:08 | That's how multiplication works."
| | 04:10 | So a string has a different behavior,
because it's a method on the string
| | 04:13 | class, whereas it works differently
when we have the multiplication as a method
| | 04:18 | on the integer class.
| | 04:20 | So as promised, let's try all these
craziness out and prove that it still works.
| | 04:24 | So here I am in my ruby_sandbox, and
I've got a file called syntactic_sugar, I'm
| | 04:28 | just going to open that up.
| | 04:29 | It's already pre-populated with everything.
| | 04:31 | I've just got those same
things that I had in my slides.
| | 04:34 | So first, I've got the nice syntactic_
sugar version, and then right below it,
| | 04:37 | I've got the not so nice version,
which we could also call syntactic_vinegar,
| | 04:41 | where it's not so tasty.
| | 04:43 | So we'll have one after another, and they
should give us the same values all the way down.
| | 04:47 | Then when we get to the arrays, I
went ahead and created a simple array.
| | 04:50 | I just called array1, [1, 2, 3],
and I've got a second one, array2.
| | 04:54 | Now this is actually an actual equal sign.
| | 04:56 | It's an actual operator where
we're doing a variable assignment.
| | 04:59 | It's not a method on an object, because
remember our variable is not an object.
| | 05:04 | That's one of the few exceptions to
things that are not objects, is a variable.
| | 05:07 | So then I'm going to go through and
just perform each of these operations to
| | 05:11 | either array1 or array2, using either
syntactic_sugar or syntactic_vinegar, and
| | 05:16 | then I'll just inspect it each
time to see what it looks like.
| | 05:18 | So let's just try it.
| | 05:20 | I'm going to go into my command line
and I'm already inside my ruby_sandbox, so
| | 05:24 | I just need to do ruby syntactic_sugar.rb.
| | 05:28 | There you go, they give the exact same
results all the way down the line, works
| | 05:32 | exactly like you would expect it to.
| | 05:34 | Thankfully though, we're able to use
the syntactic_sugar version most of the
| | 05:38 | time we're programming, but it's
still useful to know what's actually going
| | 05:41 | on behind the scenes.
| | Collapse this transcript |
|
|
6. ClassesDefining and using classes| 00:00 | In this movie, we're going
to be looking at classes.
| | 00:02 | Classes are the backbone of object-oriented
programming, because classes define objects.
| | 00:07 | They tell what an object is and
they define what an object can do.
| | 00:11 | Now we've been working with objects already.
| | 00:12 | We've seen that pretty much
everything in Ruby is an object.
| | 00:15 | But those are Ruby's objects, the
ones that are predefined for us.
| | 00:18 | This is going to be where object-
oriented programming really begins for us,
| | 00:22 | because now, we're going be able to write our
own classes that will define our own objects.
| | 00:27 | In order to get started with that, we
first need to see how to define a class,
| | 00:30 | and the syntax is very simple.
| | 00:32 | It's just class and end with the
definition of our class in the middle, very
| | 00:36 | similar to what we had when we had
methods, we had def and end, now it's class.
| | 00:40 | The one big difference
though is the naming of the class.
| | 00:44 | Methods were all lowercase with
underscores between the words.
| | 00:47 | Class names are going to
be what we called CamelCase.
| | 00:50 | We call it CamelCase because it has the
humps in the middle like that capital N.
| | 00:54 | Well, the idea here is that each word is
capitalized, but they're all smushed together.
| | 00:59 | We don't have underscores at all, so
we still have readability, because each
| | 01:03 | word is broken up with a capital
letter, but it's all one word, and most
| | 01:06 | importantly, it begins with a capital letter.
| | 01:09 | That's very important, class names
have to begin with a capital letter.
| | 01:12 | So it wouldn't matter here really if we
had SomeName and it was a lowercase n,
| | 01:16 | or if we wanted to capitalized the n.
So it's up to you when you define it,
| | 01:20 | whether you want to call it Somename
with a lowercase n or SomeName with a
| | 01:23 | capital n, but the s has to
always be capitalized for a class name.
| | 01:27 | Now classes are going to do
a number of things for us.
| | 01:30 | But one of things they're going to do
is they're going to group our code into
| | 01:33 | discrete well-categorized areas
that make it easier to work with.
| | 01:37 | So at the very beginning, what we're
going to learn to do is wrap up methods
| | 01:40 | inside there, and see how we can take
the methods that we just learned in the
| | 01:43 | last chapter, and put them inside our classes.
| | 01:46 | Let's try creating our
class with a method in it.
| | 01:49 | So to start out with, let's just
open up IRB, irb --simple-prompt.
| | 01:55 | Let's try creating a class.
| | 01:57 | So let's say just class Animal, right,
there's my capital letter A in front.
| | 02:02 | That's very important.
| | 02:03 | Then I'll start a new line and then
typically you'll indent everything after
| | 02:07 | that, so that it's very clear
where the class begins and ends.
| | 02:10 | So let's put a method in here.
| | 02:12 | Let's call it make_noise, and it's
just going to make the noise of an
| | 02:17 | animal Moo, let's say.
| | 02:19 | You'll remember that there is
a implied return there, right.
| | 02:22 | The return value is the default return
value of just the string, Moo, so that's
| | 02:26 | what will be returned,
and then end. Now it's set.
| | 02:30 | It defined it for us.
| | 02:31 | The return value was nil from doing that,
just like when we defined the method.
| | 02:35 | It didn't actually do
anything besides the definition.
| | 02:37 | We have to actually activate it, right,
actually call upon it to do something.
| | 02:42 | The way we do that with classes is that
we create a new object from the class.
| | 02:47 | So let's say Animal.new to start with.
| | 02:51 | That creates a new animal.
| | 02:52 | That's all there is to it.
| | 02:53 | But we need to hold onto that once
we've created it, so we're going to assign
| | 02:56 | that to a variable, animal = Animal.new.
| | 03:01 | Now, I created a new object, and now
that object is being held by my variables.
| | 03:06 | So I can always just say Animal,
and there it is, my variable Animal
| | 03:11 | always points to it.
| | 03:12 | Now 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:21 | make_noise is inside the class Animal.
| | 03:24 | So we need to tell Animal to do the
making of the noise, and we do that with the
| | 03:28 | dot notation, animal.make_noise. There we are.
| | 03:32 | It returns Moo.
| | 03:34 | So it did what we asked it to.
| | 03:35 | It called the method make_
noise inside that object.
| | 03:39 | So notice what we've done here, we
took an object, assigned it to a variable,
| | 03:44 | then we told that object,
call your method make_noise.
| | 03:48 | Now what it returned to us is a string
which is an object and we can do things
| | 03:52 | like make_noise upcase.
| | 03:54 | We can daisy-chain them together just
like we can any other method anywhere else.
| | 03:58 | All we've done now is write our
own method on our own custom object.
| | 04:03 | Notice also that we can't do this
animal.make_noise, but that comes back and
| | 04:08 | says, "oh, sorry, you can't do that either."
| | 04:11 | And we'll talk about that in
a little more depth later on.
| | 04:14 | But I just want you to see for now that
make_noise, we have to have that object
| | 04:18 | created from the class, then we
can tell that object to do things.
| | 04:23 | So why is defining our own objects so important?
| | 04:26 | Why is it a good thing?
| | 04:27 | Well, it's because objects let us
organize our code into well-categorized areas.
| | 04:32 | Then it's easy to find things.
| | 04:34 | So the instance of our Animal class, any
code having to do with an animal could go there.
| | 04:40 | Then if we said, oh, you know what, we
need to make a change to our code, having
| | 04:43 | to do with animals, we know right where to go.
| | 04:45 | We'd go to the Animal class.
| | 04:47 | The second benefit is that
objects carry around their classes code.
| | 04:51 | So all those definitions that we put
inside of a class, they're always available
| | 04:54 | to us, if we have that object.
| | 04:56 | So that variable now, animal,
that contains an object.
| | 04:59 | We can pass it around, we
can pass it into methods.
| | 05:02 | It's an object, just like any other object.
| | 05:04 | We can pass it in, like with a hash, we
can put it inside a hash, we can put it
| | 05:08 | inside an array, and it will always
still have all those behaviors like
| | 05:12 | make_noise available.
| | 05:14 | The third thing is that it allows
complex behaviors using very simple statements.
| | 05:19 | Imagine for a second that we have two classes.
| | 05:21 | One is a classroom, like in a
school, and the second is a student.
| | 05:26 | We want to put the student in the classroom.
| | 05:28 | Now we can just simply say classroom.add student,
and it will add the student to the classroom.
| | 05:33 | But a lot of stuff can be going on
behind the scenes there, we can be assigning
| | 05:37 | the student to a default seat, we can
be generating a name tag for them, we can
| | 05:41 | be notifying the head office
that they've been assigned.
| | 05:44 | A lot of stuff can be going on behind the
scenes, just by using very simple statements.
| | 05:49 | Last of all, our object are going
to correspond to real-world objects.
| | 05:53 | That makes it easy for us to take
abstract code, and think of it in a concrete way.
| | 05:58 | So in the example of our classroom and
student, we're not thinking about all
| | 06:02 | of the 0s and 1s that have to get
moved around to get those things to happen,
| | 06:05 | we can just think about it in very
real-world terms, classroom.add student,
| | 06:11 | and so the student gets added to the
classroom, student sit at desk, and then
| | 06:15 | we can use common sense and regular English
phrases to describe what we want our code to do.
| | Collapse this transcript |
| Instances| 00:00 | Now that we know how to define a class
and how to create an object from it, we
| | 00:04 | need to talk about instances, and have
an understanding of what an instance is,
| | 00:07 | because an instance is a fundamental
concept in object-oriented programming, and
| | 00:11 | it's going to be central
to working with classes.
| | 00:13 | Outside of programming, the typical
definition for instance might be a case or
| | 00:18 | an occurrence, an example put forth.
| | 00:20 | So what we are talking about when we talk
about programming is a very similar thing.
| | 00:24 | We are talking about an occurrence
of our class. That's what it is.
| | 00:28 | It is an object that's
being created from a class.
| | 00:32 | So when we created Animal.new, we
created an instance of the class animal, and
| | 00:37 | then we assigned it to a variable.
| | 00:38 | Now, before I was just saying it's an
object that we created, but it's an instance.
| | 00:42 | You want to start using that word.
| | 00:44 | You can use object too
when you are talking about it.
| | 00:45 | That's perfectly fine. It is an object.
| | 00:48 | But it's an instance of a class,
and that's very important for us.
| | 00:51 | I am going to go into my ruby_sandbox,
where I have got a file called classes.rb.
| | 00:57 | You can either copy the code down or
you can pull it from the Exercise Files,
| | 00:59 | but it's basically just the simple
animal class definition that we did earlier
| | 01:03 | in IRB, but now I have put it into its own file.
| | 01:06 | Right here is where we
are creating the instance.
| | 01:09 | What gets returned to us from Animal.
new as a result of the operation is an
| | 01:13 | instance, and then we are assigning
that instance to animal, and then we tell
| | 01:17 | that instance to make_noise.
| | 01:19 | Now, we can do that again.
| | 01:20 | Let's say down here.
| | 01:22 | Now we are creating a new instance.
| | 01:23 | We will call this one animal2 and this one
animal1, just so we can tell the difference.
| | 01:27 | Now we can ask animal2 to do the
same thing, animal2.make_noise.
| | 01:32 | Now, these two instances are
going to do the same thing.
| | 01:36 | Both of them are going to return Moo!
| | 01:37 | But the important point about instances
is that they are not the same, they are
| | 01:41 | two separate objects, and we will see
how to differentiate them a little later
| | 01:44 | on, but it's important to realize that
every time we call Animal.new, we get
| | 01:50 | back a new and different
instance, a different object.
| | 01:54 | It's a lot like one of those memo pads,
like a while you were out pad, and you
| | 01:58 | can pull off a separate page every
time you need to take a new message.
| | 02:02 | Each one is different, but
they all came from the same place.
| | 02:05 | The memo pad is like the class.
| | 02:07 | It has all the definitions for it.
| | 02:09 | It has all those blank spaces filled in.
| | 02:11 | It predefines how you can take a message.
| | 02:14 | But then each and every time we pull it
off, we make a new instance of it, and
| | 02:19 | we fill it out differently, with
different information for each call.
| | 02:22 | So how can we fill in the blanks on these forms?
| | 02:25 | How can we tell our animals apart so
that different animals make different
| | 02:28 | noises, or have different names,
or different numbers of legs?
| | 02:31 | Well, in order to do that we are going
to need to put variables inside of our
| | 02:34 | class definitions to hold those attributes.
| | 02:37 | Let's look at attributes in the next
movie to see how, and then I think it will
| | 02:40 | be a lot clearer when we are
dealing with different instances.
| | Collapse this transcript |
| Attributes| 00:00 | Now that we understand about instances,
we need to learn about attributes,
| | 00:03 | because attributes are how we can
differentiate between instances.
| | 00:07 | For example, if we have an instance of
our Animal class that we want to be a
| | 00:09 | pig, and then another one that we
want to be a cow, we have to have some
| | 00:13 | attribute that will give us a way to
tell the difference, and tell which one is
| | 00:16 | the pig and which one is the cow.
| | 00:17 | If you think back to our Memo Pad
example that I gave you earlier, an
| | 00:20 | attribute would be the blanks on the form that
we're going to fill out with different values.
| | 00:24 | So what we're really talking about when
we say attributes, are values that will
| | 00:28 | persist inside of an instance, and for
that we're going to need a variable, and
| | 00:33 | a variable that can store those values
and keep them around inside the instance.
| | 00:37 | It turns out that Ruby has a variable
that's especially designed for just that purpose.
| | 00:41 | We've seen it before back when
we were looking at variable scope.
| | 00:44 | It's the instance variable, and it's
prefixed with the @ sign, just a single @
| | 00:47 | sign and that's how we know right
away that it's an instance variable.
| | 00:51 | Instance variables are what we're going to use
to store the attributes inside of our instances.
| | 00:57 | You may notice that there's also
a class variable right above that.
| | 01:00 | You may think, well, why don't we use
a class variable inside of this class.
| | 01:03 | We'll get to that a little later on.
| | 01:05 | Right now, just focus on the instance
variable, because that's really what we
| | 01:08 | want to use inside of the instance of
the class, not the class itself, but the
| | 01:12 | instance of the class, and instance
variables are going to allow us to keep
| | 01:16 | track of attributes.
| | 01:17 | So let's try adding a noise
attribute to our Animal class that's inside
| | 01:22 | classes.rb, the file we've been working with.
| | 01:25 | Calling an attribute is
just as easy as saying @noise.
| | 01:29 | That's all there is to.
| | 01:29 | We're just asking for
the value of this variable.
| | 01:32 | Now the question is how do we set that
variable to begin with, so that we can
| | 01:35 | then return it and make a noise.
| | 01:38 | Well, we could just simply do Moo,
but that doesn't really give us a lot of
| | 01:41 | flexibility, then all
our instances are the same.
| | 01:44 | It's sort of like having a preprinted
memo pad, and every time you pull of a
| | 01:47 | page, it says that the call was from John Smith.
| | 01:49 | The call needs to be from different people.
| | 01:51 | So, we're going to take that away.
| | 01:53 | Let's try experimenting with
setting in a different way.
| | 01:55 | Let's say animal1.noise = "Moo
!", there we go. I'll save that.
| | 02:02 | Let's try running that.
| | 02:03 | I'll open up my command line.
| | 02:05 | Notice that I'm already inside my ruby_
sandbox, and I'll run ruby classes.rb.
| | 02:10 | You'll see that it returned an error to me.
| | 02:12 | This error indicates a very important
point about Ruby that I cannot stress
| | 02:16 | enough, which is that you do not --
never, never, never, do you have access to
| | 02:22 | instance variables from outside of the instance.
| | 02:25 | They're locked away inside of the instance,
on their own, where we can't get to them.
| | 02:30 | We can't set them, and we can't retrieve them.
| | 02:33 | Now wait a minute, you're
thinking, we can't retrieve it.
| | 02:36 | That's exactly what we're
doing when we say make_noise.
| | 02:38 | Well, that's because we can access the
methods that are inside the class, and
| | 02:43 | the methods have access to it.
| | 02:45 | So the scope of an instance variable
is inside all of the methods of the
| | 02:50 | instance, but not outside the instance.
| | 02:52 | So, if we want to get to those values
of the instance variable, we have to do
| | 02:57 | it by using methods.
| | 02:58 | It's a very important point.
| | 03:00 | So instead of doing this line that
won't work, instead let's set an instance
| | 03:05 | that will set it for us.
| | 03:06 | So let's call it set_noise.
| | 03:09 | For now, let's just say @noise = "Moo!".
| | 03:13 | Now this doesn't give us the
flexibility that we're looking for just yet, but
| | 03:18 | we'll get there in one second.
| | 03:19 | Let's go ahead and just try running this first.
| | 03:21 | Of course, we'll need to call that method.
| | 03:23 | So let's say animal1.set_noise.
| | 03:26 | Let's save it and let's try running that.
| | 03:29 | So once again here I am.
| | 03:30 | I'm going to run ruby classes.rb again,
and you'll see that it did call it.
| | 03:34 | Now, notice a couple of things here,
first of all, notice that now my two
| | 03:38 | instances are different.
| | 03:40 | The first one has a noise of moo, the
second one has a noise of nil, because
| | 03:43 | nothing was ever set, we
didn't call set_noise down here.
| | 03:46 | We just didn't make noise.
| | 03:48 | So the first point is we can see now we
have two separate instances that are different.
| | 03:53 | The second point is notice that the
instance variable persisted inside the
| | 03:59 | instance, and we still have access to
it when we called a different method.
| | 04:04 | So we set it here, we've
retrieved it here. It didn't matter.
| | 04:08 | It was still around.
| | 04:09 | We still had access to it, even
though they're in two different methods.
| | 04:12 | Now as I notice, we're still missing
that flexibility to make our instances
| | 04:16 | sort of be whatever we want, but we
know how to do that with regular method
| | 04:19 | calls, set_noise equals to noise, and
now @noise can just equal noise, and
| | 04:25 | there's no conflict.
| | 04:26 | This is a instance variable,
this is a local variable.
| | 04:29 | They are two different types.
| | 04:30 | So as far as Ruby is concerned,
they are completely different.
| | 04:33 | They point to two different locations.
| | 04:35 | There's no conflict there.
| | 04:36 | So now when we say set_noise, we
need to specify, Moo, and then let's go
| | 04:41 | ahead and do the same thing down here animal2.
set_noise, and let's make it equal to Quack.
| | 04:48 | There we go.
| | 04:48 | Let's try it saving it.
| | 04:51 | We'll go back to the Terminal, and we'll
run them, and I get back Moo and Quack.
| | 04:55 | So now we have two different instances
with an attribute that we have access to.
| | 05:00 | In the next couple of movies, I want to
explore the idea of how we can get and
| | 05:03 | set these attributes using methods a
little bit further, and show you some
| | 05:06 | shortcuts that I think will help a lot.
| | Collapse this transcript |
| Reader/writer methods| 00:00 | At the end of the last movie, we
saw how we could access our instance
| | 00:03 | variables using methods.
| | 00:05 | I want to explore that idea a little
further in this movie by looking at
| | 00:08 | reader and writer methods.
| | 00:10 | Now this is a very common feature of
object-oriented programming languages,
| | 00:13 | sometimes in other languages,
they're called getter and setter methods.
| | 00:16 | Either one is fine.
| | 00:17 | You can use either name, typically in
Ruby, we're going to call them reader
| | 00:20 | and writer methods.
| | 00:22 | So, here is the code where we left off
inside classes.rb, what we're looking
| | 00:26 | for is a pairing of something that
will set a value for us and something that
| | 00:30 | will get a value for us, and that's exactly
what we already have with our two methods.
| | 00:34 | The first one is a setter
method or a writer method.
| | 00:38 | So we're setting the value of noise
equal to a value, and this is the classic
| | 00:43 | format for what a setter method would look like,
set_noise equal to a value. It sets it for us.
| | 00:48 | Then we have make_noise.
| | 00:50 | Typically, we would call this get_noise.
| | 00:52 | It's a getter method.
| | 00:53 | We need to change it here
when we call it as well.
| | 00:57 | In either one what do you say, make the
noise or get the noise is up to you, but
| | 01:00 | the idea is that we are getting that value back.
| | 01:03 | One of these methods sets
it, one of them gets it.
| | 01:06 | Now the important thing about these
two methods is that they give us access
| | 01:09 | control over these instance variables.
| | 01:12 | So for example, if we were to take
away get_noise, now we have no way to
| | 01:16 | get that value back.
| | 01:18 | Of course, we could write another
method that would do it for us, but our
| | 01:21 | getter method is gone.
| | 01:23 | Same thing here, if we were to take away
set_noise, now we have no way to set it
| | 01:27 | by calling a method.
| | 01:29 | There might be another convoluted way,
maybe a back end way that we could
| | 01:32 | get that value set, but we need a setter
method if we want to be able to do it directly.
| | 01:37 | Now set_ with whatever the attribute
name is and get_ is very common in a lot of
| | 01:42 | programming languages.
| | 01:44 | In Ruby though, we can make use of
that syntactic sugar that we looked at
| | 01:47 | earlier, and so we can take get
_out and simply ask for noise.
| | 01:52 | So it asks Animal to do the method noise,
which returns the instance variable, noise.
| | 01:58 | It's a very commonsense approach.
| | 02:00 | So now animal1.noise and animal2.
noise just returns that to us, where the
| | 02:05 | syntactic sugar comes in is that we can
do the same thing with set, we can take
| | 02:09 | away set and just say noise=(noise).
| | 02:14 | Remember how we did that earlier?
| | 02:15 | So noise =, and we saw that the
parenthesis are optional, we can take away
| | 02:20 | those, and now it feels just like
we're assigning it to a regular variable.
| | 02:26 | So it feels like we're assigning
it to that attribute, but we're not.
| | 02:30 | We're actually passing it through
a method to get to that attribute.
| | 02:34 | That's a very important difference.
| | 02:36 | So we get the usage, as if we're just
assigning it, but something more complex
| | 02:40 | is going on behind the scenes.
| | 02:41 | Now if we didn't have this method,
then as we saw earlier, noise= "Moo!"
| | 02:45 | won't work anymore.
| | 02:47 | It'll say oops, sorry, I don't have a method
called noise =, we have to write that method.
| | 02:52 | That's our setter method.
| | 02:53 | So now that we have our class
rewritten in the sort of standard way that Ruby
| | 02:57 | does these reader and writer methods
or getter setter methods, let's save it
| | 03:01 | and just try it out.
| | 03:02 | I'll go into the Terminal, notice I'm
inside my ruby_sandbox, ruby classes.rb,
| | 03:07 | and it still works exactly as we would expect.
| | 03:09 | Now some of you are probably thinking,
well, that's cool, and I'm glad that I'm
| | 03:12 | able to just use this = and everything,
but are you telling me that every time I
| | 03:16 | have an attribute, I
have to write this pair out?
| | 03:20 | Well, fortunately not, there is a shortcut,
and I'll show you that in the next movie.
| | Collapse this transcript |
| Attribute methods| 00:00 | We've seen how we can use reader, writer
methods in order to access our attributes.
| | 00:04 | We saw how we could even use Ruby's
syntactic sugar to make the process a little easier.
| | 00:09 | But one thing that's striking is you
may be thinking, well, what if I have a
| | 00:11 | large class that has lots of attributes?
| | 00:15 | Are you telling me that I have to go
through and write a reader and a writer
| | 00:19 | attribute for each and
every one of those attributes.
| | 00:22 | Well fortunately, the answer is no, you
don't have to do that over and over again.
| | 00:26 | Ruby provides a very nice shortcut,
because this is done so often that we can
| | 00:30 | just simply use an attribute method.
| | 00:33 | These are also frequently called attr
methods or attr_* methods, and that's
| | 00:40 | because they all begin with attr_
and that * serves as a wild card for
| | 00:45 | everything that comes after it.
| | 00:46 | The three methods that we're going to
be looking at are, attribute reader,
| | 00:49 | attribute writer, and attribute accessor.
| | 00:52 | Each one of them is actually a
method that we're putting into our class.
| | 00:57 | When that method gets called, it takes
a symbol that we provide after it and
| | 01:02 | turns it into a method
for us that we can then use.
| | 01:06 | So it's exactly the same thing as
if we had typed it out the long way.
| | 01:10 | You can guess what each of them does.
| | 01:12 | Reader creates a reader method, writer
creates a writer method, and accessor
| | 01:16 | creates both a reader and a writer method.
| | 01:18 | So for example, attr_reader with the
symbol name passed to it as an argument,
| | 01:24 | will tell your class, hey!
| | 01:26 | class while you're booting up and
getting started, create this definition for
| | 01:30 | me, create this method that I can then call.
| | 01:32 | It's exactly the same as if we had
typed it out ourselves, exactly the same.
| | 01:37 | Same thing for attribute writer.
| | 01:39 | It's the same as if we had typed
that same thing we did for noise, if we
| | 01:42 | had attribute_writer : noise, then it would
give us def noise = (value) @noise = value.
| | 01:51 | And that's exactly what it would create
inside the class for us, just by typing
| | 01:55 | this one simple line, and where that
really pays off, of course, is when we want
| | 01:57 | to be able to read and write.
| | 01:59 | So attr_accessor creates two methods for
us, and saves us a whole lot of typing.
| | 02:05 | If we want to create more attribute
accessor methods, we just put a comma after
| | 02:09 | the first one and put another symbol
and then a comma and so on for all of the
| | 02:13 | different methods that we wanted to create.
| | 02:15 | It really is that easy, but it was
important that I showed you the long way of
| | 02:19 | doing it before I showed you the
shortcut, so that you would really have an
| | 02:22 | understanding of what was
happening under the hood.
| | 02:24 | So let's try using these attribute methods.
| | 02:27 | So in our classes.rb file that we've
been working with, I'm not going to
| | 02:31 | change the class Animal's noise, we already
have those methods, I'm not going to replace them.
| | 02:36 | Let's create some new ones
just to see how easy it is.
| | 02:38 | attr_accessor and then let's make the
animal's name, so we'll name our animals,
| | 02:45 | Tom, Fred,something like that.
| | 02:47 | Then we could have attribute writer, and
let's set the attribute writer equal to
| | 02:53 | the color of the animal.
| | 02:55 | Let's say the attribute reader will
set equal to the number of legs the
| | 02:59 | animal has and then arms.
| | 03:01 | We can put commas so that we could
indicate that we have more than one.
| | 03:04 | So let's stop and realize
what it did for us here.
| | 03:06 | When we first load our class, right,
when it first reads in this file, it will
| | 03:11 | start processing the class.
| | 03:12 | It will come here and will say, "Ah!
| | 03:14 | The attr_accessor method.
| | 03:16 | I need to execute this command."
| | 03:18 | What it does is creates attribute
accessor for a name, which looks pretty much
| | 03:23 | like what we have here for noise,
except with name in place of noise.
| | 03:27 | So now, we'll have an instance
variable called @name that we can access.
| | 03:31 | We can access it in the same syntactic
sugar way that we were accessing noise.
| | 03:35 | Then once it's done with that, it will
come to the attribute writer line and
| | 03:39 | it'll say, "okay, let's
create a writer for color."
| | 03:41 | So that will create only this one for
color, there will not be a method like
| | 03:46 | this that will allow us to ask for
the colored by just saying .color.
| | 03:50 | Then last of all, it will come
to the reader line and say, "Ah!
| | 03:52 | Let me create a reader for legs and
a reader for arms." Not a setter.
| | 03:57 | There'll be no way to set it.
| | 03:58 | So let's just try making use of those.
| | 04:00 | Let's say here with animal1, let's say,
animal1.name = Steve, and then let's ask
| | 04:08 | it to puts animal1.name
so that it will output it.
| | 04:13 | So we should have been able to write to it,
and to read from it with those two steps.
| | 04:17 | Let's try doing animal1.color = "black
", and then let's do puts animal1.color.
| | 04:29 | Now we should be able to write to it,
but not read from this, so we're expecting
| | 04:32 | an error there already.
| | 04:35 | Then let's try last of all animal1.,
and we'll just do legs = 4, and
| | 04:42 | animal1.legs, we'll need a puts
in front of that. There we are.
| | 04:48 | So that should return these values to
us, but we're going to get a couple of
| | 04:50 | errors, because we're trying to read
and write when we shouldn't be allowed to.
| | 04:53 | So let's just see how far we get.
| | 04:55 | Let's go into the command line, notice
that I'm already inside my Ruby sandbox
| | 04:59 | and I'll run ruby classes.rb, and
sure enough, undefined method color.
| | 05:04 | So the method color doesn't exist.
| | 05:06 | It did, notice, come back
and report Steve, first.
| | 05:11 | But then it got to here and it said,
no, sorry, I do not have this method.
| | 05:15 | It didn't complain here.
| | 05:16 | It has that method.
| | 05:17 | It didn't have the reader method.
| | 05:19 | Now we could put our own in.
| | 05:21 | Let's just do that, def
color, and let's return @color.
| | 05:26 | Maybe we want to do something a
different though, maybe we want to say return,
| | 05:31 | The color is, something like that.
| | 05:37 | Now let's run it, we'll still get an error
later on, but we'll get a little further.
| | 05:41 | Now we get, The color is black, so now
we get undefined method legs=, because we
| | 05:47 | did not allow it to be a writer.
| | 05:48 | It's just a reader.
| | 05:50 | So we need another way to set the legs.
| | 05:52 | Let's say that we have something here.
| | 05:54 | Let's create another method at the beginning
called def, and setup_limbs, we'll call it.
| | 06:00 | When we set up limbs, we're going to say,
well, legs should be equal to 4, and
| | 06:06 | arms is going to be equal to 0.
| | 06:08 | So let's just try running that real
quick, we'll need to run that setup.
| | 06:12 | Let's do it right here, animal1.
setup_limbs, and let's run it.
| | 06:21 | Now we get -- oops, sorry, we still
have that legs=, we've got to take that out
| | 06:24 | of there, because that won't work.
| | 06:26 | We can't set it anymore, but now we
can still read it back. Let's try that.
| | 06:31 | Undefined local, puts animal1, that's
my mistake, little typo. There we go.
| | 06:36 | So now everything returns to us.
| | 06:40 | So take a moment and look at what we did there.
| | 06:43 | We used these attribute accessors,
writers and readers, to make these
| | 06:47 | definitions for us much easier.
| | 06:49 | We can still define it ourselves, we
can do something different when we define
| | 06:53 | it, or we can still have access to
those through other methods, but it's just
| | 06:57 | the simple access that we'd lose, right,
we don't have that direct access to
| | 07:01 | them unless we write something for
ourselves or use these attribute methods.
| | 07:07 | Because creating these kinds of
attributes that have access control is done so
| | 07:11 | commonly, Ruby provides this
very handy shortcut for us.
| | Collapse this transcript |
| Initialize method| 00:00 | Very often in Ruby when we create an
instance of a class, we want that instance
| | 00:04 | to do some initialization, settings
some default values or calling some default
| | 00:08 | methods that will happen right at the beginning.
| | 00:11 | We saw a little bit of this in our
last movie, when we wrote the set_limbs
| | 00:15 | method, and that was a method that we
called that set the values of the legs and
| | 00:20 | arms, instance variables on our animals
so that they had a default value there.
| | 00:24 | Well, instead of calling a separate
method that will set those up, let's instead
| | 00:27 | use the initialize method.
| | 00:28 | So here I'm in the Animal
class that I've been working with.
| | 00:32 | Creating an initialize method is
just as easy as calling initialize.
| | 00:36 | That's all there is to it.
| | 00:37 | Now I no longer have to
call setup_limbs, boom! Done!
| | 00:41 | It's just like that. That simple.
| | 00:42 | Now initialize will set
any values that I want here.
| | 00:46 | It will also allow me to execute some other
Ruby code, I can call other things in here.
| | 00:51 | Maybe I want to output something.
| | 00:53 | Let's try puts "A new
animal has been instantiated".
| | 00:59 | That's a fancy word for saying we
created an instance of it that has been
| | 01:03 | instantiated, a new
animal has been instantiated.
| | 01:06 | Let's go into the command line, you'll
notice that I'm already inside my Ruby
| | 01:10 | sandbox, and I'll just run ruby classes on it.
| | 01:14 | There we are, A new animal
has been instantiated, right?
| | 01:18 | So it both sets values, but also calls
any Ruby code that we want to put in there.
| | 01:22 | So that can be any number of things, but
every time an instance of this class is
| | 01:26 | created, do these initialization routines.
| | 01:29 | Now notice that we never call
initialize explicitly, initialize is sort of a
| | 01:33 | magic method name that happens
automatically on every object.
| | 01:38 | So when we call Animal.new, the new
method creates it, but the first thing that
| | 01:44 | does upon creating it is
run this initialize method.
| | 01:47 | Now initialize, like all methods also
allows us to pass in arguments to it.
| | 01:52 | So let's say, for example, legs, arms,
and actually let's go ahead while we're
| | 01:57 | at it, and let's put noise at the beginning.
| | 02:00 | Well now, we have access to legs and arms,
and while we're at it, let's go ahead
| | 02:05 | and set @noise = noise.
| | 02:08 | So it works exactly like a regular
method, there is nothing special there, but
| | 02:11 | how do we pass these values into initialize?
| | 02:15 | Well, it turns out that the new
method takes values and passes them right
| | 02:21 | on into initialize.
| | 02:22 | As soon as it creates the new object, it
passes initialize, whatever values it has.
| | 02:26 | So we could for example, say, Moo is
the noise, and legs, and arms, 4, and 0.
| | 02:32 | So now we no longer have to set noise,
and we never set legs that was being set
| | 02:38 | before in the methods. So let's try that.
| | 02:40 | Let's go back and run ruby classes.
| | 02:43 | You'll notice that now, I'm getting
a wrong number of arguments error.
| | 02:47 | That's on my second animal, because
once we start adding arguments to new, it
| | 02:52 | always expects them, unless
we set some default values.
| | 02:55 | We saw that before with methods,
there is nothing really new there.
| | 02:57 | But let's just do Quack, there we are,
so we don't have to set this anymore.
| | 03:02 | Now for legs, let's set the default equal
to 4, and the arms, the default, equal to 0.
| | 03:07 | So now we don't have to pass
those values if we don't want to.
| | 03:11 | When we run it, everything
works exactly like we would expect.
| | 03:14 | So that's all there
really is to using initialize.
| | 03:17 | It works just like a normal method, the
only difference is that it gets called
| | 03:20 | automatically, and that values we pass
into new, get passed on to initialize.
| | Collapse this transcript |
| Class methods| 00:00 | So far we've been creating instances of
our classes, and then we've been calling
| | 00:04 | methods on that instance.
| | 00:06 | We can also call methods directly on the
class itself, and we call those class methods.
| | 00:11 | The other ones of course
are called instance methods.
| | 00:13 | So in this movie we're going to look at
how we can create our own class methods.
| | 00:17 | We've already seen how to call a class
method, even though we didn't know it,
| | 00:20 | and that was Animal.new.
| | 00:22 | New is a class method.
| | 00:24 | It's a built-in class
method to every Ruby object.
| | 00:28 | So, we can call new, and it
returns a new instance to us.
| | 00:31 | But it's still a method.
| | 00:32 | It's a method that exists on the class
even when we don't have an instance, and
| | 00:38 | that's what you are going
to use class methods for.
| | 00:40 | We are going to use a class method when
we want the class, to do something for us.
| | 00:44 | Even though there may not
be an instance in sight.
| | 00:46 | It doesn't matter, maybe there are
instances, maybe there aren't.Defining class
| | 00:49 | methods is very simple.
| | 00:51 | We do it just the same way we do
instance methods except that we put the self
| | 00:55 | keyword in front of it.
| | 00:56 | So, self.method_name let's us
know that that is a class method.
| | 01:01 | It's something that our
class itself will execute.
| | 01:04 | Now the self keyword in Ruby applies
to whatever object we're currently in.
| | 01:09 | So, in this case, where we're in the
definition of the class, self is the class itself.
| | 01:15 | If that still sounds very abstract and
hard to get your head around, I think
| | 01:18 | it'll be easier once we
actually try a couple of examples.
| | 01:21 | So, let's start by adding a class
method to our Animal class, in the classes.rb
| | 01:27 | file we've been working with.
| | 01:28 | I am going to do that above
initialize, this is mostly by convention.
| | 01:31 | You can put it anywhere in the file you
want, but typically you'll put the class
| | 01:35 | methods above the instance methods.
| | 01:37 | So, def self and let's create one
called all_species, just like we were talking
| | 01:42 | about, and this will return a list of
all possible species that this class knows
| | 01:47 | about, obviously not all species that exist.
| | 01:50 | And I am just going to paste in an array there,
| | 01:54 | [cat, cow, dog, duck, horse, and pig].
| | 01:54 | So, when we ask the class, hey!
| | 01:57 | Tell me about all the species that are there.
| | 01:59 | It doesn't have to have an instance,
it already, the class itself can tell
| | 02:03 | us that information.
| | 02:04 | We don't have to create an
instance in order to get to it.
| | 02:06 | So, let's just save it. Let's try it.
| | 02:08 | Before we even get to an instance down
here, let's just do puts, and we will ask
| | 02:12 | the Animal class for all_species, right?
| | 02:17 | This will put out an array.
| | 02:19 | Let's go ahead and do an inspect on
the end of the array too, just so that it
| | 02:22 | outputs it in a little
nicer format for us to read.
| | 02:24 | So, let's switch in our command
line, notice I am already inside my
| | 02:28 | ruby_sandbox, ruby classes.rb, and there we are.
| | 02:33 | Just see that it outputs the array.
| | 02:35 | So, there are three
important things to notice there.
| | 02:38 | The first is that we didn't have an
instance when we called it, the second is
| | 02:43 | that the way we called it, which is to
call it directly on the class, and the
| | 02:46 | third, was that the kind of information
that we returned was general information
| | 02:51 | about the class itself.
| | 02:53 | Now as I noted earlier, new is an
example of another class method.
| | 02:57 | We can create our own class methods
that do things for us instead of just
| | 03:01 | returning information.
| | 03:02 | So, let's add another method, this one
will actually do something instead of
| | 03:06 | just returning information, let's say
a def self create_with_attributes, and
| | 03:14 | the attributes we are going to pass
are going to be the noise that it should
| | 03:17 | make and the color.
| | 03:20 | And then all we are going to
do is create a new class, right?
| | 03:24 | Create an instance of the class, and
then make sure that it has these attributes
| | 03:29 | before we return it to the user.
| | 03:31 | So, we'll still need to create one
Animal.new, and you'll remember when we
| | 03:36 | created new, now we need to provide a noise.
| | 03:39 | That's a required attribute.
| | 03:41 | So we'll pass in noise, and let's go
ahead and capture that as a local variable.
| | 03:46 | Animal =, and then we could set, animal.color,
because we set attr_writer to color up here.
| | 03:53 | So, we can write to color and we will
set it equal to color, and then last of
| | 03:57 | all, we'll return the Animal object itself.
| | 04:00 | So, we are going to return the actual
animal instance, so we are calling a
| | 04:03 | class method, just like new, but
what happens in the end is it returns an
| | 04:08 | instance of it to us.
| | 04:10 | So, we'll try this out, before we do it,
I just want to point out one more thing
| | 04:13 | which is that I am calling Animal.new
here, because I am inside the class, I can
| | 04:18 | also make use of self.
| | 04:19 | Once again, the keyword refers
to the object that we are in.
| | 04:22 | It's not only for use in defining
our methods, we can make use of it
| | 04:26 | throughout the method.
| | 04:28 | Let's drop-down, and let's
try this create with attributes.
| | 04:31 | Let's just do it to animal2 here.
| | 04:33 | Let's try create_with_attributes,
and now in addition to Quack!
| | 04:39 | I just need to tell it white, and then
puts animal to noise, and the very last
| | 04:44 | thing we puts animal color, right?
| | 04:48 | And I have a method here that
will report the color to me.
| | 04:51 | So, let's try that out.
| | 04:53 | ruby_classes.rb, and there we go.
| | 04:55 | We are getting the Quack!
| | 04:56 | and we are getting the color as white.
| | 04:58 | So, both are being set by our
new create with attributes method.
| | 05:02 | So, hopefully now you see not only
the mechanics of how to work with class
| | 05:06 | methods, because I think that's pretty
easy, but also conceptually, when you
| | 05:10 | would use it, I think that
might be a little bit harder.
| | 05:12 | It's things that are at the class
level that do not have to have an instance
| | 05:16 | around, things that are more
general than a specific case.
| | Collapse this transcript |
| Class attributes| 00:00 | So far we've seen how we can create
methods on our instances, and those are
| | 00:04 | called instance methods.
| | 00:05 | We've seen how we can create methods on our
classes, and those are called class methods.
| | 00:09 | We also saw how we could put
attributes on our instances.
| | 00:12 | It would store values that
were particular to the instance.
| | 00:16 | In this movie, we are going to take a
look at class attributes, which are the
| | 00:19 | same thing, but attached to our classes.
| | 00:22 | That is, they are for storing
values that apply to the class generally.
| | 00:26 | The same way that the class
methods apply to the class generally.
| | 00:30 | And the way that we'll store these
values is going to be in a class variable.
| | 00:34 | We took a peek at this before, when
we were looking at instance variables.
| | 00:37 | It's in the line right above
it with two @ signs in front it.
| | 00:40 | So, if you see the two @ signs, it's
a class variable and it will persist
| | 00:44 | anytime we have the class,
even if we don't have an instance.
| | 00:48 | Instance variables are going to
be only inside of the instance.
| | 00:52 | That's the only time we'll have those.
| | 00:53 | Let's see how we can use class variables.
| | 00:56 | Finding a class variable is very simple, we
just simply use @@ and let's say species =.
| | 01:02 | That is now the class variable.
| | 01:05 | It will persist anytime we have the class.
| | 01:08 | Now the one problem with this is that
this doesn't get defined unless we call
| | 01:13 | this method all_species, right?
| | 01:14 | We don't have an initialize method,
like we do with a class or we could do
| | 01:18 | this when it boots up.
| | 01:20 | Instead what we do, if we want it to
happen automatically, as we put it in the
| | 01:24 | body of the class, then it
happens when the class is defined.
| | 01:28 | So, the initialization of the
class is when it gets read in.
| | 01:32 | So, the Processor starts
reading in the file and it says, "Ah!
| | 01:35 | I am going to create a class, I am going
to call it animal, I am going to create
| | 01:38 | an attr_accessor, a writer, and a
reader, and I am going to set the class
| | 01:42 | variable species equal to this array.
| | 01:45 | Then I am going to set up these
definitions for what I'll do inside the class
| | 01:49 | and inside my instances" and so on.
| | 01:51 | So this is the way that we define class
methods that we want to exist from the
| | 01:54 | beginning, all right?
| | 01:55 | It's the same as putting them in
the initialize method for an instance.
| | 01:59 | So 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:08 | have to even have an
instance. Let's try it out.
| | 02:11 | Notice down here, I've already
got the call to all_species, right?
| | 02:14 | puts Animal.all_species, I don't have
an Instance at this point, but first
| | 02:18 | Instance gets created here.
| | 02:20 | So, we're looking up here where
we don't even have an Instance.
| | 02:23 | Let's open up the command line, notice
that I am already inside ruby_sandbox,
| | 02:27 | ruby_classes.rb, there we go.
| | 02:30 | It still pulls up those values.
| | 02:32 | That is now being stored in a class
variable which is also known as a class attribute.
| | 02:37 | Now this is certainly a perfectly
appropriate time to use a class variable,
| | 02:42 | because we are using it for information
which is general for the whole class, so
| | 02:46 | then we have the ability to say oh!
| | 02:48 | When we are creating a new Instance
maybe, maybe we want to make sure that it's
| | 02:52 | one of these species.
| | 02:53 | That's a possibility.
| | 02:55 | We can now check that
against our @@species variable.
| | 02:58 | Another very common use case is
if we want to keep track of things.
| | 03:02 | Let's say we have @@total_animals,
very common usage, total_animals = 0.
| | 03:08 | And then whenever we initialize a new
animal, all we have to do is say oh!
| | 03:12 | By the way, while you are
initializing it, let's take @animals and do += 1.
| | 03:17 | Now the number of animals increases
every time we create one, so we can keep
| | 03:21 | track of how many animals have been created.
| | 03:23 | That's one way to do it.
| | 03:25 | Another great use of class methods is
not just to keep track of the number of
| | 03:28 | animals but to actually keep
track of the instances themselves.
| | 03:31 | So, let's say here we make
this instead current_animals.
| | 03:35 | So, if the animals that have been
instantiated, the ones that have been created
| | 03:38 | and instead of being 0, it's
going to be an empty array.
| | 03:42 | So, now down here we'll say well, current
animals should instead be appended the value self.
| | 03:50 | In this case self is an Instance, it's
the instance that's just been created
| | 03:55 | and that keyword will plug that object
not the class, remember self is a magic
| | 03:59 | word for the object.
| | 04:00 | It's inside at that moment.
| | 04:01 | But this time, it's going to be the Instance.
| | 04:04 | Up here, when we used it, it was the class.
| | 04:05 | So, we are using it for an Instance
and saying put this Instance inside the
| | 04:09 | current animals array, so
we can keep track of it.
| | 04:12 | So, let's drop down here to the bottom
and we'll put, puts Animal to class, and
| | 04:18 | now we want to ask it for its current_animals.
| | 04:22 | That's what we want to ask it
to return is the current_animals.
| | 04:25 | Let's go ahead and put inspect on it.
| | 04:27 | So, we can see what that array is
going to look like in a nice friendly way.
| | 04:29 | So, let's try that out and let me give
you a hint this is not going to work.
| | 04:33 | We've done ruby_classes, at the end
undefined method, current_animals.
| | 04:37 | Now that's because the same thing is
true with our class attributes and class
| | 04:42 | variables as was true with our Instances.
| | 04:45 | We cannot access those values,
those attributes from outside the class.
| | 04:50 | In order to do that, we
need Reader and Writer methods.
| | 04:54 | Let's see those in the next movie.
| | Collapse this transcript |
| Class reader/writer methods| 00:00 | We saw how instance attributes used
Reader Writer methods to give access to them
| | 00:04 | from outside of the instance.
| | 00:06 | Now in this movie we are going to see
how we can use Class Reader/Writer methods
| | 00:10 | in order to get access to our class
attributes from outside of the class.
| | 00:15 | So I am still inside the classes.
rb document we've been working with
| | 00:18 | throughout this chapter, and in the
last movie we tried to call the current
| | 00:21 | animals method on animal, right?
| | 00:24 | And we can't do that because we
don't have a current animals method.
| | 00:27 | We have a current animals attribute, right?
| | 00:30 | A class variable that we set, but we
don't have a method to be able to read it.
| | 00:34 | Well writing that method is trivial, right?
| | 00:36 | We know how to do that, self.current animals.
| | 00:40 | And then what should it return?
| | 00:42 | It should return current animals.
| | 00:45 | That's all there is to being able to
create a Reader method for this that will
| | 00:49 | let us return that value.
| | 00:50 | In fact we had already done
that here with all species.
| | 00:53 | We could just simply shorten this to
species and then it kind of fits more with
| | 00:57 | the typical Ruby style of giving
us a little bit of syntactic sugar.
| | 01:01 | In fact we could have a Writer method,
def self.species=, and then let's ask it
| | 01:08 | to provide an array and we will give
it a default value of an empty array.
| | 01:13 | And then, of course that's going to take
@species and it's going to set it equal
| | 01:18 | to the array that we've asked it to send out.
| | 01:21 | So now just like we had for the
Reader/Writer methods we created for our
| | 01:25 | instance methods, we have the
same thing here for our classes.
| | 01:29 | Species is the Reader, species= is the Writer.
| | 01:32 | The only difference is that we are
saying it's a class method and it's a class
| | 01:37 | variable being returned.
| | 01:38 | Otherwise it's exactly the
same thing as what we had before.
| | 01:41 | Let's go ahead and just
prove to ourselves that worked.
| | 01:43 | I am down here before we asked for
species, we'll need to change this from all
| | 01:47 | species to just species, right?
| | 01:48 | or that will break.
| | 01:50 | Let's set that value, let's say Animal,
tuck in the class directly, species=,
| | 01:56 | and let's throw in a couple of species here.
| | 01:57 | Let's say frog and fish.
| | 02:01 | So it's just something that's very
different than what we had before.
| | 02:03 | Now we'll just go back into our command line.
| | 02:06 | Notice that I am already in my ruby_
sandbox, ruby classes.rb, there we go.
| | 02:11 | Now the value of species has been set.
| | 02:14 | So I will set it to something
different and I read it back.
| | 02:17 | I use my Reader/Writer attribute on it.
| | 02:18 | You'll also notice that the other
request you made down here at the end, for
| | 02:22 | current animals, one we were trying to
do in the last movie that also works now
| | 02:26 | as well because I
created a Reader method for it.
| | 02:29 | So now it returned to objects for us.
| | 02:32 | What we are seeing here is a summary
of the way that it tries to represent an
| | 02:36 | object as text, right an object is not text.
| | 02:39 | But it tries to give us
something that sort of looks like it.
| | 02:41 | It shows us what all those
instance variables inside there are.
| | 02:44 | So we've got the first animal which
has color black name Steve, noise is Moo,
| | 02:49 | the second animal color white,
noise equals Quack! and so on.
| | 02:53 | So we've got those two
objects inside of our array.
| | 02:55 | We can also apply the Each
method to it instead of inspecting it.
| | 02:59 | We saw how to use the Each iterator to
loop through each of those items one at a
| | 03:03 | time and then we could ask it for its
color, or its sound, or something like
| | 03:06 | that, and so that will tell us
then all the current animals.
| | 03:10 | It will keep track of the inventory for us.
| | 03:12 | So that's really all there is to
creating these class methods that are
| | 03:15 | Readers and Writers.
| | 03:16 | The one thing though is that we had
before this attr_writer and we had
| | 03:22 | attr_reader and attr_accessor.
| | 03:25 | We don't have anything like
that at the moment in Ruby.
| | 03:28 | That may be something that comes
in a future version, some kind of a
| | 03:31 | convenience method for that.
| | 03:32 | Right now you have to write it
yourself, which isn't as big of a problem,
| | 03:36 | because these happen a lot less
often than the other kinds of attributes.
| | 03:39 | The other ones happen very
frequently so we need the shortcuts.
| | 03:42 | For the class ones you'll have to
write them out yourself or you could create
| | 03:46 | your own method that would do that for you.
| | 03:49 | In Ruby on Rails, for example
they've created one called cattr_accessor.
| | 03:54 | So you can make use of it if you are
using Ruby on Rails you can get access
| | 03:58 | using the cattr_accessor.
| | 04:01 | But that's something that doesn't
exist in the core Ruby currently.
| | 04:04 | It's something that was added on.
| | Collapse this transcript |
| Inheritance| 00:00 | In this movie we're going to
talk about class inheritance.
| | 00:03 | Now this is not the same as
inheritance in the real world where you inherit
| | 00:07 | money and objects and things like
that from your ancestors, instead in
| | 00:11 | object-oriented programming inheritance
refers to inheriting the methods and the
| | 00:15 | attributes of another class.
| | 00:17 | It's a very common feature in almost
all aspects of object-oriented programming
| | 00:21 | and Ruby is no different.
| | 00:23 | Let's say for example that we have our
Animal class that we have been working with.
| | 00:26 | Up until now we've been creating
instances of that Animal class.
| | 00:29 | We can create several instances
and then we can give attributes to
| | 00:33 | those instances, right?
| | 00:34 | Cow, pig, and duck, we can give them sounds.
| | 00:36 | Well, instead of doing that we
could also have the ability to create
| | 00:40 | subclasses, classes that would inherit
information from animal which would be
| | 00:45 | their own unique class.
| | 00:47 | So instead we can have the animal class
and create a new class called cow, and
| | 00:52 | that cow class would inherit all of
the behaviors of the animal class, but it
| | 00:57 | would be its own class at the same time.
| | 00:59 | We could also create another one
called pig and another class called duck.
| | 01:02 | All of these would inherit from
animal but each would be its own class.
| | 01:05 | They could have its own unique
behaviors separate from the animal class, even
| | 01:09 | though they sort of come from the same route.
| | 01:11 | We call the parent class animal, the
Superclass or you can just call it the
| | 01:16 | Parent informally, but technically it's
the Superclass, and these other ones are
| | 01:19 | the Subclasses and we call
those the Children informally.
| | 01:23 | So we talk about the parent and child
relationship a lot of time between two
| | 01:26 | different classes, what we are really
talking about is the superclass and the subclass.
| | 01:30 | And then from these classes we could
create our instances, we could have a Cow
| | 01:33 | instance and give it the
attribute Moo for its noise.
| | 01:37 | We could do the same thing for pig,
make it Oink and Duck would be Quack.
| | 01:40 | So we would end up with in the
end are still three instances.
| | 01:43 | But there are three instances that
might have very different behaviors.
| | 01:48 | For example, a duck might have a whole
bunch of methods related to being able to
| | 01:52 | swim, but a cow doesn't
need to have those methods.
| | 01:55 | A cow might have a lot of methods
about how to graze for grass, but the duck
| | 01:59 | doesn't necessarily need those methods.
| | 02:01 | But at the same time all of them
could inherit some common attributes, from
| | 02:06 | animal, like the fact that they have legs,
like the fact that they make a noise,
| | 02:10 | those would be inherited.
| | 02:11 | I think I have illustrated it enough.
| | 02:13 | Let's try to put into practice.
| | 02:14 | I am still in my classes.rb
file that I have been working with.
| | 02:18 | I am going to use a feature of
Textmate here to just fold up some of these
| | 02:21 | methods that we've been working with.
| | 02:23 | It's kind of a nice feature that Textmate
just kind of let you get things out of your way.
| | 02:26 | So that's what I am doing here.
| | 02:27 | If you are not using Textmate that's fine.
| | 02:29 | It just clears up my screen a little
bit and gives me a little more room.
| | 02:31 | I am going to just create a new class and
we are just going to call this class Cow.
| | 02:36 | The way we indicate that it is a
subclass of the animal parent class is with
| | 02:41 | the less than sign, and then the name
of the parent class, and you'll notice
| | 02:45 | that it gives me a nice italicized
thing there in Textmate to let me know that
| | 02:49 | that's what's happening.
| | 02:50 | So, the cow class inheriting from animal.
| | 02:54 | That's all we've got so far.
| | 02:55 | Let's just try with only that.
| | 02:58 | Let's try to drop down here at the very
bottom after we've done all this stuff
| | 03:01 | that we've already been working with.
| | 03:02 | Let's do a new one.
| | 03:03 | Let's say maisie, the cow,
is going to be Cow.new.
| | 03:08 | Let's just try that out, see what
happens, if we just try and create a new
| | 03:12 | instance of our class Cow.
| | 03:14 | Let's go to our command line.
| | 03:16 | Notice I am already in my
ruby_sandbox, ruby classes.rb.
| | 03:21 | So it goes through and it does
everything as we would expect.
| | 03:23 | And then right here it
says, "woop, wait a minute.
| | 03:25 | Initialize wrong number of arguments.
| | 03:28 | You sent 0 and I was expecting 1."
| | 03:30 | Well, that's because it
inherited this initialize method.
| | 03:35 | Initialize is expecting us to
pass in a noise. So let's try that.
| | 03:39 | Let's try passing in a noise when we create it.
| | 03:41 | So the noise will be Moo!
| | 03:43 | And then let's go ahead while we are down here,
and let's say well, let's puts maisie.noise.
| | 03:49 | Let's ask what Maisie's noise is?
| | 03:50 | So let's go back ruby
classes, we'll run one more time.
| | 03:54 | This time it works.
| | 03:55 | You'll see a new animal has been instantiated.
| | 03:58 | That's happening in that Animal parent
class, but we inherited that into the Cow
| | 04:03 | class, and then it comes back with Moo!
| | 04:05 | So, it did successfully created.
| | 04:07 | It created it using this initialize
method and we were able to use this noise
| | 04:12 | method to return a value all just
by sub-classing Cow from Animal.
| | 04:18 | Now there is a difference here,
right, if we were to say do say puts
| | 04:22 | animal1.class and puts maisie.class.
| | 04:28 | Then we'll actually see those class names.
| | 04:30 | Let's run that one more time. Oops!
| | 04:31 | Sorry I mis-spelled maisie, and let's
try that again, maisie, there we are.
| | 04:38 | Now it comes back and it tells us, aw!
| | 04:39 | one is an animal and another one is a cow.
| | 04:41 | Now we can actually tell the difference.
| | 04:43 | Now we have the ability to know is this
thing I am working with a cow, we don't
| | 04:47 | have to give it an attribute of cow it
can be the class cow and have different
| | 04:52 | behaviors that we can add on.
| | 04:53 | We could just as easily go in and
start adding new features to our cow class
| | 04:58 | that would exist only in cow.
| | 05:00 | They would not be in animal.
| | 05:01 | So we get everything that was in animal,
plus anything we define inside cow.
| | 05:06 | And that's really all there is to the
fundamentals of creating Inheritance.
| | 05:09 | It's a good way to help organize
your code, but there are also some very
| | 05:12 | powerful things that we can do when we
start borrowing features from other classes.
| | 05:17 | The one last note I want to make on this
is that unlike a lot of object-oriented
| | 05:20 | languages, we cannot have multiple inheritance.
| | 05:24 | In Ruby we can inherit from one
and only one superclass, right, not
| | 05:28 | multiple, only one each time.
| | 05:31 | If you want to have different behaviors
we'll use modules for that, we'll talk
| | 05:34 | about that in the next chapter.
| | 05:35 | So I just want to make a footnote,
if you are used to working with other
| | 05:37 | languages that use multiple inheritance,
here you can only inherit from one class.
| | Collapse this transcript |
| Subclass overriding| 00:00 | In the last movie we saw how we could
inherit all of the methods and attributes
| | 00:05 | from a parent superclass
into the child subclass.
| | 00:10 | But what about, when you don't
want to take all of the methods?
| | 00:12 | Let's say you want everything that's
in the parent class except there are a
| | 00:16 | couple of things you want to do
differently than the parent did them.
| | 00:19 | Well, we can do that by
overriding methods in the subclass.
| | 00:22 | So here I am in the same classes.rb
file we've been working with throughout the
| | 00:26 | chapter and I've got class Animal and
then I've created a subclass of Cow, which
| | 00:31 | doesn't have any attributes or methods in it.
| | 00:33 | It's inheriting all of its methods and
all of its attributes from the Animal class.
| | 00:37 | Now, let's take a look here at color.
| | 00:40 | Right now we have a method
inside our Animal class called Color.
| | 00:43 | The color is blank.
| | 00:45 | Let's try and access that.
| | 00:46 | Down here we'd already created an
instance of the Cow called maisie.
| | 00:50 | Let's drop down one more line here and
let's say puts maisie.color, all right.
| | 00:55 | So we'll save that.
| | 00:57 | Let's just run it and see
what we get to start with.
| | 00:59 | So I am inside my ruby_sandbox
already, we'll run ruby classes.rb.
| | 01:04 | The color is nothing, so it hasn't been set.
| | 01:06 | We need to set Maisie's color first.
| | 01:09 | We can see that one of the ways we can
set it is using create with attributes
| | 01:13 | when we create it, right,
that allow us to set the color.
| | 01:15 | So let's try that instead.
| | 01:17 | Let's try now using Cow create with attributes.
| | 01:20 | We still have this method that's
available to us because it came from the
| | 01:23 | parent class, and now let's create the color,
and let's say that Maisie is a yellow cow.
| | 01:28 | All right, so yellow cow will save it.
| | 01:31 | Now let's just try running it one more
time, ruby classes, the color is yellow.
| | 01:35 | So now Maisie has the color yellow.
| | 01:38 | So now let's see how we
could override this behavior.
| | 01:40 | Now that we see what it does
by default, it's real easy.
| | 01:43 | We just simply write def color, and
then whatever we want our new thing to be.
| | 01:48 | So let's say The cow's color is.
| | 01:52 | We'll do the exact same thing, but now
it's going to tell us that it's a cow.
| | 01:56 | So that's something that would be in
the Cow class, and the animal class would
| | 01:59 | just say the color is whatever it is,
but the cow knows that it's a cow.
| | 02:03 | Let's try it one more time. There it is.
| | 02:06 | The cow's color is yellow.
| | 02:07 | So now we've overridden it.
| | 02:09 | Now it didn't change up here for these
other animals we created where we created
| | 02:12 | something from the Animal class
directly, we just have the colors white.
| | 02:16 | All we did was say inherit all the
behaviors of animal, but after you do that
| | 02:22 | overwrite the Cow class with this
one method, it really is that easy.
| | 02:26 | The reason why this works is
because Ruby reads in the class
| | 02:29 | definition sequentially.
| | 02:30 | So the first thing it does is it makes
the inheritance, then it redefines color.
| | 02:35 | Now we can redefine things as often
as we want, right, redefine color.
| | 02:40 | We could say my color is
and then do the color, right?
| | 02:43 | Let's just save that, go
back to our command line.
| | 02:49 | My color is yellow.
| | 02:50 | It didn't object to the fact that we had
more than one method this one got overwritten.
| | 02:54 | This might as well not exist at all
because we not only overwrote the parent
| | 03:00 | superclass, we overwrote
our own method a second time.
| | 03:04 | So it's no problem, Ruby doesn't mind
us having more than one but whatever the
| | 03:07 | last definition is that's the one that wins.
| | 03:10 | That's the one they got
assigned and kept inside the class.
| | 03:13 | The fact that Ruby lets you override
these methods is actually one of the
| | 03:16 | really cool features of Ruby because we could
override any class method in exactly this way.
| | 03:21 | Let me show you what I mean.
| | 03:21 | Let's go back to our command line.
| | 03:23 | I am going to open up a new
irb session with simple prompt.
| | 03:26 | So we've gone back in irb.
| | 03:28 | Let's just create a simple array, x=1, 2, 3.
| | 03:33 | Now if we ask it to turn that array into
a string, x. to s, we get back 1, 2, 3.
| | 03:40 | That's what the two-string
method does for an array.
| | 03:42 | It just smashes everything together.
| | 03:44 | Well, let's just say we don't like
that behavior, we'd like to do something
| | 03:47 | a little different.
| | 03:48 | All we have to do is open up class array.
| | 03:51 | Now this is the Ruby class array, we
are changing the behavior of a fundamental
| | 03:55 | Ruby class, we have the ability to do that.
| | 03:58 | And then let's redefine it, def to_
s, and now it can be whatever new
| | 04:03 | definition we want.
| | 04:04 | I am going to say self.join and then,
space and then we'll need to end and end.
| | 04:12 | Now we've changed the definition of this
one method, everything else about class
| | 04:17 | array is still the same.
| | 04:18 | It was already defined.
| | 04:19 | What we did essentially was reopen the class.
| | 04:22 | Just for a second, make a new
definition, and it went ahead and put that into
| | 04:26 | that previous class definition that was there.
| | 04:28 | It's not the same thing as a
superclass and a subclass, but we are overriding
| | 04:32 | the existing method.
| | 04:33 | And now let's just try it again.
| | 04:35 | We'll just go up to the array x.to
string, and now I get this new behavior.
| | 04:40 | I think that's a very powerful
feature of Ruby, the fact that we have the
| | 04:43 | ability to override methods, not just
in parent classes and subclasses, but any
| | 04:48 | class method we want.
| | 04:49 | At any time, we can stop and override
it including the Ruby Core Library, and
| | 04:54 | that's a really powerful feature.
| | Collapse this transcript |
| Accessing the superclass| 00:00 | In the last movie we saw how we could
override some of the methods that are
| | 00:03 | subclass inherited from its superclass.
| | 00:06 | But sometimes we don't want to
override the method entirely.
| | 00:09 | We want to still take in most of that
behavior from the parent class, but we
| | 00:13 | just want to tinker
around the edges a little bit.
| | 00:15 | Well, we can do that, thanks to the
keyword Super, and that's how we'll access
| | 00:19 | the superclass from the subclass.
| | 00:22 | So I've already got my class Animal that
we've been working with and I created a
| | 00:25 | subclass called Cow.
| | 00:27 | Let's create another subclass now.
| | 00:29 | Let's call it subclass Pig.
| | 00:31 | That will be subclass of Animal so it
will inherit all those behaviors from
| | 00:35 | Animal, but let's
override something inside of it.
| | 00:37 | Let's say we'll take the noise
method that we've been working with.
| | 00:40 | So it normally just returns noise.
| | 00:42 | Let's override that.
| | 00:43 | def noise, and we've seen
how to do basic overriding.
| | 00:46 | Let's say Hello, right, so that's just
going to return Hello instead of whatever
| | 00:51 | the animal's noise is.
| | 00:52 | Let's go ahead and instantiate it down here.
| | 00:54 | Let's say wilbur is going to be equal
to Pig.new, and we know that we need to
| | 01:00 | provide something to the initialize
method, so that's going to be just Oink!
| | 01:04 | So now it will have a noise but then
when we say puts wilbur.noise, it will
| | 01:12 | return to us, Hello.
| | 01:13 | Let's go to our Terminal and try it, ruby
classes, notice I am already in my ruby_sandbox.
| | 01:19 | So there we are, we just get
back Hello, we didn't get back Oink!
| | 01:22 | we overrode it successfully.
| | 01:23 | We've seen how to do that.
| | 01:25 | Now though if we want to call what was in the
parent method, all we have to do is put super.
| | 01:30 | So let's go ahead and just comment out
Hello for now, and we will just have that
| | 01:34 | super method in there so
we can see what it does.
| | 01:36 | So let's run it again, Oink!
| | 01:40 | So effectively in this
case I did not override it.
| | 01:43 | I started to override it, and then I
said, oh -- and by the way Super means do
| | 01:48 | whatever the parent was going to do,
call the noise instance on the parent.
| | 01:53 | Go find that and do that original version.
| | 01:56 | That's what super does.
| | 01:57 | Now let's swap this around for a
second and let's just say we call super
| | 02:01 | and then we call Hello.
| | 02:03 | Now think about what you think
this is going to do before we do it.
| | 02:06 | I'll save it and let's go back and
let's run it one more time and we just get
| | 02:11 | Hello, we don't get the Oink!
| | 02:13 | And I want to make sure that you understand why.
| | 02:15 | Super calls this parent method, right,
I am just going to fold up Cow here so
| | 02:19 | it's out of our way.
| | 02:20 | It calls this which returns the value at noise.
| | 02:23 | So this returns at noise to this
function, okay, doesn't get returned back to
| | 02:30 | where we called this noise method.
| | 02:33 | It just returns it here.
| | 02:34 | Then the next thing we do is Hello,
which is the same thing as return Hello.
| | 02:39 | Now if we were instead to do something
like parent_noise = super, and then we
| | 02:47 | said Hello and also, and
then we did parent_noise.
| | 02:53 | Now it will return both of them to us.
| | 02:56 | So super is just a method.
| | 02:58 | That's all it is, and it can return a
value, but it doesn't automatically return
| | 03:03 | it back as this return value here.
| | 03:05 | We still have to return at the end of it.
| | 03:06 | So I just want to make sure that's clear.
| | 03:08 | Let's try that out, Hello and also Oink!
| | 03:12 | That's all there is to being able to
access these parent methods is this keyword
| | 03:16 | super, but just make sure that
you understand what it's doing.
| | 03:19 | It's actually calling that method, and
then it's just as if we called any other
| | 03:23 | method, we still have to
work it in the same way here.
| | 03:25 | So it doesn't matter if we call it before
we do something or after we do something.
| | 03:28 | It's just simply a method call.
| | Collapse this transcript |
|
|
7. ModulesNamespacing| 00:00 | In this chapter we will be
taking a look at Ruby's modules.
| | 00:03 | Put it simply, modules are
wrappers around our Ruby code.
| | 00:07 | Now, you may be thinking, wait a
minute, isn't that what a class was?
| | 00:10 | A class was a way for us to roll up
different methods and attributes into a wrapper.
| | 00:14 | Well, modules work in a very similar
way, but modules have one important
| | 00:18 | difference from classes.
| | 00:20 | They can't be instantiated.
| | 00:21 | We can never have an instance of a module
the way that we have an instance of the class.
| | 00:26 | Instead, we are going to use our
modules in conjunction with our classes.
| | 00:29 | That will make more sense as we examine the
two reasons why we would want to use modules.
| | 00:33 | We will look at the first one in
this movie, which is namespaces.
| | 00:37 | If you come from another
programming language, you may already have
| | 00:39 | familiarity with namespacing.
| | 00:41 | It's a very common concept.
| | 00:43 | If not, imagine that you have a classroom
that has two students in it named Sophia.
| | 00:47 | The teacher would end up calling one of
them Sophia M. and the other one Sophia
| | 00:51 | S., so that she could tell them apart,
and that way she could address questions
| | 00:54 | to the right Sophia and not just simply
say Sophia and have both of them try and
| | 00:58 | answer at the same time.
| | 00:59 | Well in Ruby, in the same way,
namespaces allow us to have class names which
| | 01:05 | don't conflict, so that we
can tell the class names apart.
| | 01:07 | Let me give you a
concrete real-world illustration.
| | 01:11 | Let's suppose for a moment that we have
developed a website for online dating.
| | 01:14 | So our users are going to login,
they are going to fill out personal
| | 01:16 | information, and then they will get
matched with people that they might want to date.
| | 01:20 | Well, in the process of building that
site, we might need a class called Date,
| | 01:23 | which would set up the
meetings between the two people.
| | 01:25 | But our usage of Date is very different
from the standard Ruby definition, which
| | 01:29 | is a calendar date, a year, a month, and a day.
| | 01:32 | Now, if they have the same name, we
will have a conflict, because Ruby won't be
| | 01:35 | able to tell them apart.
| | 01:36 | For example, we would have dinner
equals date new and we would be talking about
| | 01:40 | this meeting that should happen, but
then when we try and say on what calendar
| | 01:43 | date it ought to happen, we would
be saying dinner.date = Date.new.
| | 01:47 | Ruby can't tell those two things apart.
| | 01:49 | To avoid this name conflict, we can
use a module to namespace our date.
| | 01:52 | All we have to do is wrap
our class in a module name.
| | 01:56 | So here you can see I have put the
module Romantic around the class.
| | 02:00 | Romantic is still capitalized and
everything is exactly the way a class name
| | 02:03 | would be, but it's a wrapper around our class.
| | 02:06 | Now when we want to get a new instance of our
date for our dating site, we use a new notation.
| | 02:12 | Now we say dinner = Romantic::
| | 02:16 | Date, and that tells it that we are
talking about this namespaced date.
| | 02:20 | The one that belongs inside the
Romantic module, that is kept completely
| | 02:24 | separate from the dinner.date = Date.new.
| | 02:29 | Now it knows that's Ruby's internal date.
| | 02:32 | Modules are named exactly
the same way that classes are.
| | 02:34 | It's just a wrapper that goes around it.
| | 02:36 | So module Romantic is the example I have given.
| | 02:39 | We can make that anything we want.
| | 02:40 | That double colon lets you
know that it's been namespaced.
| | 02:43 | So we are not just talking about the
standard date, we are talking about date
| | 02:46 | within the namespace Romantic.
| | 02:49 | Namespacing really is that easy.
| | 02:51 | Now, I don't want you to think that
namespacing is only to keep you from
| | 02:55 | conflicting your classes with Ruby's classes.
| | 02:58 | It could be to keep it from conflicting
with another class that you have written
| | 03:01 | inside the same site.
| | 03:02 | There might be two different contexts
where we need to use a certain class name.
| | 03:06 | One very common use of namespacing
is if we were going to try and release
| | 03:10 | our classes out as open source, so that
other people could use them in their projects.
| | 03:15 | We can't anticipate ahead of time what
their class names will be, so to make
| | 03:19 | sure that our classes don't conflict
with whatever they have got, we would
| | 03:22 | namespace them and we might wrap them in a
module that had some kind of unique name.
| | 03:26 | Maybe our name or our project's name
or something like that, so that we could
| | 03:30 | make sure that it always stayed separate and
didn't conflict with whatever they already had.
| | 03:33 | I think that's enough on
namespacing to make the point.
| | 03:36 | Let's take a look at the second more
powerful use of modules, which is as Mix-ins.
| | Collapse this transcript |
| Mixins| 00:00 | In the last movie we saw how
to use modules for namespacing.
| | 00:04 | In this movie we are going to look at
the second more powerful use of modules,
| | 00:06 | which is to use them as mix-ins.
| | 00:08 | Let me explain what the term mix-ins means.
| | 00:10 | Unlike some other programming
languages, Ruby doesn't let us have
| | 00:14 | multiple inheritance.
| | 00:15 | If we have a class, that class can inherit its
behaviors from only one parent or superclass.
| | 00:21 | That's it, just one.
| | 00:22 | If we need additional functionality
to be brought in that's shared among
| | 00:26 | classes, we will need to put it in a
module, and then we can take that module
| | 00:29 | and all its functionality and mix
it in to any class that needs it.
| | 00:33 | It's a very powerful way for
us to keep our code organized.
| | 00:36 | In my ruby_sandbox I have now got a
file called person.rb that I created.
| | 00:41 | It's a very simple class for person.
| | 00:43 | It has some attributes.
| | 00:44 | It has a couple of methods that work
with those attributes, nothing that we
| | 00:48 | haven't seen before.
| | 00:49 | Now, if you are like me, you
frequently end up with a case like this, where
| | 00:52 | you have class Person.
| | 00:53 | But then you want to say, oh, well, I
also need a class Teacher, and maybe
| | 00:58 | let's also have a class Student, and we
end up with all these different classes
| | 01:02 | which are very similar.
| | 01:03 | We want the full name method
to be in all three of them.
| | 01:05 | Now, we could just copy it three times,
and with something as simple as the full
| | 01:09 | name method, that's not a terrible
choice, but if it was a really complex
| | 01:12 | method, that would be a really bad choice.
| | 01:15 | So instead what we want to be able to do
is use modules as mix-ins for this behavior.
| | 01:20 | So let's create a new module up here.
| | 01:22 | Now, this is not going to wrap around our class.
| | 01:24 | It's going to be a standalone module.
| | 01:26 | module ContactInfo.
| | 01:28 | Notice I did CamelCase here,
just like a class name.
| | 01:31 | Now, as I said at the beginning of this
chapter, this module is just a wrapper for code.
| | 01:36 | So let's take all of this functionality,
every single bit of it, and let's just
| | 01:40 | cut it out of our Person class
and put it into our module class.
| | 01:43 | So now our class is no longer wrapping
all that functionality, the module is.
| | 01:48 | Well, that's great, except now we
need a way to get the module and all its
| | 01:52 | functionality into our class, and
we do that with the Include method.
| | 01:56 | So include ContactInfo.
| | 01:57 | We have to write the module name.
| | 02:00 | We will include that module
and all of its functionality.
| | 02:03 | It's exactly the same as if we typed
all of those lines in right in place of
| | 02:09 | where the word include is.
| | 02:10 | So let's try that out.
| | 02:11 | I am going to save that document.
| | 02:12 | I am going to go into my command line.
| | 02:14 | Notice that I am already inside my ruby_sandbox.
| | 02:17 | I am going to open up irb with simple-prompt.
| | 02:18 | I am going to load in that file, person.rb.
| | 02:23 | So load just simply reads
the contents of the file.
| | 02:26 | That's exactly like if we had typed Ruby and
the name of the file from the command line.
| | 02:30 | Now, you may need to provide a full
path to this file if you are not inside the
| | 02:34 | directory where it already exists, but if
it succeeds, it will come back and say true.
| | 02:38 | So now that file is loaded.
| | 02:39 | The difference between running from the
command line is now we can interact with it.
| | 02:42 | So let's say person = Person.new, person.
first_name = "Joe", person.last_name = "Smith".
| | 02:52 | Then we should say puts
person.full_name. There we go.
| | 02:59 | We do have our attributes there
and we do have that full name method.
| | 03:02 | All of that functionality from contact
information was just dropped in to person.
| | 03:06 | Of course the real benefit to that is
that not only can it be in Person, but now
| | 03:10 | we can also put it inside Teacher and
inside Student, and now, if we decide to
| | 03:14 | make a change to one of these methods
and we say, oh, wait a minute, you know
| | 03:17 | what, I actually want two
spaces before the zip code.
| | 03:20 | We make that change there and it
happens everywhere that module is included.
| | 03:24 | Now, module functionality is also
inherited, so I just want to point out that we
| | 03:28 | could also do something like this.
| | 03:29 | Student, let's say, it will inherit from Person.
| | 03:32 | Now I don't need to even declare this
anymore, we can have different attributes here.
| | 03:36 | Let's say that the Student has many
books and grades, and our Teacher up here
| | 03:43 | can have some different
attributes, accessor, lesson_plans.
| | 03:49 | So each of our classes is now
different, but all three of them have
| | 03:53 | contact information.
| | 03:54 | These two have it because they
explicitly included it, the Student inherited the
| | 03:58 | behavior of Person and just added a
few attributes to it, and inheriting from
| | 04:01 | Person inherited that
module's behaviors as well.
| | Collapse this transcript |
| Load, require, and include| 00:00 | In the last movie, where we were
looking at modules as mix-ins, we defined our
| | 00:04 | module and the classes all in the
same file, and we just made sure that the
| | 00:08 | module came before the class, so that
Ruby would have a definition for the
| | 00:12 | module, so that it could include it
when the class definition came up.
| | 00:16 | Well, more typically, we would
not put those in the same file.
| | 00:19 | We would break them into separate files,
and our modules would start to exist
| | 00:23 | in their own files, like code libraries,
that we could just mix-in that library
| | 00:27 | whenever we needed.
| | 00:28 | So frequently you will end up with
these small little module files that you can
| | 00:31 | draw upon whenever you need.
| | 00:33 | Well, if we break it off into a
separate file, what that means is that we have
| | 00:36 | to have a way of making sure that
Ruby has loaded in that module and knows
| | 00:41 | that definition before we try and mix
it in to one of our classes, like our
| | 00:45 | Person class, and that gives us the
perfect opportunity to take a look at
| | 00:48 | three Ruby commands:
| | 00:49 | Load, Require, and Include.
| | 00:52 | Because the difference between these
three methods frequently trips beginning
| | 00:55 | programmers up, let's take a look at them.
| | 00:57 | So in the last movie I created my
Person class and then I also have a
| | 01:00 | module, ContactInfo.
| | 01:01 | What I want to do now is
break that up into its own file.
| | 01:04 | So I am going to start by just doing
a Save As, and I will save this file
| | 01:08 | as contact_info.rb.
| | 01:11 | Now its in its own file,
notice I am in contact_info.rb.
| | 01:14 | I am going to erase
everything that's not in that module.
| | 01:17 | So now I have just a module definition in there.
| | 01:19 | Let's move that out of the way.
| | 01:21 | Let's go into the sandbox, and let's
open up person.rb again, and now let's
| | 01:25 | do the opposite here.
| | 01:26 | Let's take away everything that's
not our Person class definition.
| | 01:30 | Now, I have still got Teacher
and Student here. That's fine.
| | 01:32 | I am just going to leave them for now.
| | 01:33 | Typically you would probably break them
off into their own files, but I am not
| | 01:36 | going to worry about them while I go
ahead and make the main point that I want
| | 01:38 | to make, which is that, before we can
include contact_info in this file, Ruby
| | 01:44 | needs to know about
contact_info. Let me show you.
| | 01:47 | Let's go into the command
line. Let's open up irb.
| | 01:50 | Notice I am already in my
ruby_sandbox, simple_prompt.
| | 01:54 | Let's go ahead and just load in that
person file, just like we did in the last movie.
| | 01:59 | So person.rb, load that in. Wait a minute.
| | 02:01 | It says uninitialized
constant Person::ContactInfo.
| | 02:05 | It's trying to find contact_info, and it can't.
| | 02:08 | That's because we haven't loaded it in.
| | 02:09 | Ruby doesn't know what it is, doesn't
know how to find it, so it can't include it.
| | 02:13 | So what we need to do is load,
and then contact_info.rb, true.
| | 02:20 | Now I am going to hit the up arrow
twice and let's load in person.rb now.
| | 02:24 | No problem this time.
| | 02:25 | So as long as contact_info is loaded in
first, we are okay to load in person.rb.
| | 02:31 | So we could say that person.rb
depends on contact_info, it's a dependency.
| | 02:37 | So what we want to do is take this line,
load, and put it at the top of the file.
| | 02:42 | So that way the first thing that person.
rb does is it loads in contact_info, and
| | 02:48 | then it can go ahead and
execute. Let's Save it.
| | 02:50 | Let's try it.
| | 02:51 | I will quit out of irb.
| | 02:53 | Let's go back into irb, so we get a fresh copy.
| | 02:56 | There is nothing stored in memory yet, and
now let's just try load person.rb. True.
| | 03:01 | It worked, because it first loaded in
contact_info and then loaded in this file.
| | 03:06 | So we have solved the problem.
| | 03:08 | Now incidentally, this is a path here.
| | 03:10 | It's not just a file name.
| | 03:11 | It's the path to a file.
| | 03:12 | We will be talking more about paths
when we get to the section on files.
| | 03:16 | But it works the same way that paths do.
| | 03:18 | If you are used to working with
Linux or DOS or anything like that.
| | 03:22 | We can provide an absolute path, or we can
provide a relative path to get to that file.
| | 03:26 | So this solves the problem that we
started with and it also illustrates how Load
| | 03:30 | works and how Include works.
| | 03:32 | So Include is used exclusively
for bringing modules in as mix-ins.
| | 03:37 | That's what its for.
| | 03:38 | Include has nothing to do with loading in files.
| | 03:41 | We use Load for that.
| | 03:42 | Now, let me show you something about
Load that's very important, which is that
| | 03:45 | let's say load person.rb again, it
loaded it again, loaded it again, and so on.
| | 03:51 | Every time it returns true,
because it loaded in those files again.
| | 03:55 | If we have already loaded it in, if
Ruby has already seen that definition,
| | 03:58 | there's no reason to do it a second time.
| | 04:00 | Each and every time that it loads in person.rb.
| | 04:03 | It's also executing this
load of contact_info again.
| | 04:06 | But we don't need it to
load those every single time.
| | 04:10 | Let's say that we had Teacher
and Student in their own class.
| | 04:13 | We would want then to also have a
statement at the top that would say
| | 04:16 | load contact_info.rb, because each one of
those would have the same kind of dependency.
| | 04:22 | Well, we don't want to
load contact_info three times.
| | 04:24 | That's waste of time and energy, and
it might actually have a negative impact
| | 04:27 | on our program if somewhere along the way we
have made changes to what's in contact_info.
| | 04:32 | So a better way to do it, and which we
will typically see instead is Require.
| | 04:37 | Require works exactly the same as Load,
the only difference is that Require
| | 04:41 | keeps track of the fact that it's
already included the file and only includes it
| | 04:45 | if it hasn't been loaded before.
| | 04:47 | Now, it's possible to trick Require by
having some different paths to get to
| | 04:51 | files, but for the most part it's pretty good.
| | 04:53 | Now, let's also put it here.
| | 04:54 | Let's say require.person.rb.
| | 04:58 | Now, the first time I executed, it
should return true to me, because it is
| | 05:01 | requiring it for the first time.
| | 05:03 | But now Require has added that file
to its list of files that it knows it
| | 05:07 | required, and now when I say require
person.rb, it comes back and says false.
| | 05:12 | It did not bring the file in again.
| | 05:14 | It is still there, but
require didn't do anything.
| | 05:17 | So if you need to actually refresh
the code and bring something in a second
| | 05:21 | time, you will want to use Load, but
more often than not what you want is just
| | 05:25 | to bring this library in, so that Ruby
knows about it, and then once you have
| | 05:29 | required it, you don't need to read it in again.
| | 05:30 | Ruby already knows about it.
| | 05:32 | Now, you will want to pay careful
attention if you have been programming
| | 05:34 | in other languages, because these
may have different meanings than they
| | 05:37 | had in those languages.
| | 05:38 | For example, if you are working in PHP,
Include, it means load in a file, not
| | 05:43 | include a module, so just be careful about that.
| | 05:46 | So just to make sure that you
are clear on the differences.
| | 05:48 | Load loads in a source file
every single time its called.
| | 05:52 | It will always return true if
the file is successfully loaded in.
| | 05:56 | Require loads a source file only
once, after that it keeps track of the
| | 06:01 | fact that its loaded in, the fact
that it knows about it, and it doesn't
| | 06:03 | bother loading it again.
| | 06:04 | It says, "oh yes, I have already seen that."
| | 06:07 | Then last of all, Include is
what we use for including modules.
| | 06:11 | It has nothing to do with
files and reading files in.
| | 06:14 | It's only for bringing in
that mix-in behavior of modules.
| | Collapse this transcript |
| Enumerable as a mixin| 00:00 | Before we leave modules and move on, I
want to give you a little bit of insight
| | 00:04 | into way that Ruby uses modules
inside its standard library of classes.
| | 00:08 | Now, we've seen a number of methods so
far, like sort, detect, select, reject,
| | 00:13 | collect, and inject and even more that are
shared between a number of different classes.
| | 00:17 | We saw how we could use these on arrays
and hashes and ranges and strings, and
| | 00:22 | that they are used in more classes as well.
| | 00:23 | And they might have slightly
different behaviors on each one, but the same
| | 00:27 | functionality essentially
is part of all these classes.
| | 00:30 | When you have shared functionality
like that, it's a good indication that a
| | 00:33 | module may be at work, and that's
exactly what's happening with these classes.
| | 00:36 | So here I am taking a look at the Ruby
documentation at ruby-doc.org in the core
| | 00:41 | library, and I've got a definition for array.
| | 00:44 | Now we see all the methods that are
in array, but notice here, it says
| | 00:47 | Included Modules>Enumerable.
| | 00:50 | Enumerable is an included module in array.
| | 00:52 | Let's take a look at Hash, scroll down
Included Modules>Enumerable and Range,
| | 00:59 | Included Modules>Enumerable.
| | 01:01 | String, same thing.
| | 01:02 | It has Comparable and Enumerable in there.
| | 01:05 | So the module that's being included in
every case is Enumerable, and enumerable
| | 01:09 | is just something that can be counted, right.
| | 01:11 | If we have a set of things that can be
counted, then we ought to be able to do
| | 01:13 | something with them.
| | 01:14 | We got to be able to sort them, we
got to be able to collect them to search
| | 01:18 | through them, and that functionality
is mixed in to all of those sets, right.
| | 01:23 | Arrange is a set, an array
is a set, a hash is a set.
| | 01:26 | So all of them have this enumerable behavior.
| | 01:28 | Now if you look at the definition here
for Enumerable, it tells you that it's a
| | 01:31 | mixin and it provides collection classes,
things which have a collection, with
| | 01:36 | several traversal and searching
methods and with the ability to sort.
| | 01:39 | The one caveat is that class must
provide a method each, which is going to
| | 01:43 | yield successive members of the
collection, and we saw how to do that when
| | 01:47 | working with code blocks.
| | 01:48 | We saw how to yield up a value.
| | 01:50 | And then it goes on to say that if
we want to use the max, min, or sort
| | 01:53 | functionality, then we'll also need to
provide the comparison operator so that
| | 01:57 | it will know how to
compare two different values.
| | 01:59 | So we can see how Ruby goes about
sharing this functionality between
| | 02:04 | the different classes.
| | 02:05 | And you could override any of those
methods just like we saw you could do
| | 02:08 | earlier if you want different
functionality, but if not, we can include the
| | 02:12 | module and get all of
its functionality for free.
| | 02:14 | All we have to do is provide this each method.
| | 02:17 | Now here's where the
advanced extra credit part comes in.
| | 02:20 | We can mix in that
Enumerable module for ourselves.
| | 02:24 | Now while you can often get the same
functionality just by putting an array
| | 02:28 | inside your object, and using Enumerable off
that array, it's really not that hard to do.
| | 02:33 | So let's go ahead and just see how to
do it even though most of the time, it's
| | 02:36 | really an unnecessary step
that you won't want to do.
| | 02:39 | I have got a simple class here in to_
do_list.rb and I just have a simple
| | 02:43 | attribute called items that I'm
initializing as an empty array and then I have
| | 02:47 | given some sample usage
down here in the comments.
| | 02:49 | We'd just initialize it, assign a list
of to-do list items to the items array,
| | 02:54 | and then we could call select
on this array. It's an array.
| | 02:58 | It already has enumerable mixed into it.
| | 03:01 | So that's why I say this
is not strictly necessary.
| | 03:04 | Let's make the to-do list itself enumerable.
| | 03:06 | All we have to do is say include Enumerable.
| | 03:09 | We don't need to do any kind of require
or anything, because it's already in Ruby.
| | 03:13 | If Ruby is loaded then we have Enumerable.
| | 03:15 | So include Enumerable.
| | 03:17 | That will then give us all those features.
| | 03:18 | But if you remember, the
documentation told us that we need to have an
| | 03:21 | each method declared.
| | 03:23 | So it knows what is going to be
rendered up, what are the enumerable things.
| | 03:27 | We could have a lot of different
things inside this to-do list, right.
| | 03:30 | We could can have several attribute accessors.
| | 03:31 | So we could have items, we
could have completed items, so on.
| | 03:36 | So it wants to know what
exactly are you enumerating.
| | 03:39 | We'll tell it, well, it's going to be
items, items.each and then we'll just put
| | 03:43 | in a code block, we know how to do this
earlier and yield that value for items.
| | 03:48 | So it will just yield up this value
each and every time to Enumerable, so
| | 03:52 | Enumerable can make use of it.
| | 03:53 | That's all we have to do to get
most of that Enumerable functionality.
| | 03:57 | Let's save it and try it out.
| | 03:59 | Let's go into command line.
| | 04:01 | Notice I am already in my ruby_sandbox.
| | 04:03 | I'll open up irb with simple prompt and
now, let's do our require and the file
| | 04:08 | is to_do_list.rb true.
| | 04:12 | So it loaded it in.
| | 04:14 | Now let's say list equals ToDoList.
new and let's give our items a value.
| | 04:21 | items equals and we'll just use the
same ones, laundry and dishes and vacuum.
| | 04:28 | Okay, so there is our array of items.
| | 04:31 | Now we already know that we
could do lists.items.select.
| | 04:36 | That's the one we are using before select
each item, if the item length is greater than 6.
| | 04:42 | So it comes back with laundry.
| | 04:44 | But what we've now done is we've put
that enumerable on the object itself.
| | 04:48 | So now list.select returns the same thing.
| | 04:52 | We're essentially just sending the
same array to it, but we don't have to be.
| | 04:56 | We could be putting in
something much more complex here.
| | 04:59 | So what we were yielding up is some
complicated calculated value maybe, maybe we
| | 05:03 | are mashing together a
couple of different objects.
| | 05:06 | The important part is just that we've told
Enumerable what collection should be enumerated.
| | 05:10 | It can be a manufactured collection or a
simple collection like an array, but we
| | 05:14 | just have to tell it here is each item.
| | 05:16 | That you will iterate through by using
the each method, and from there, we get
| | 05:20 | all of this other behavior built in.
| | 05:22 | This is really isn't the most
practical thing to use in the world.
| | 05:25 | So don't go start using
Enumerable all over the place.
| | 05:28 | It really is for a sort of special
complex case where you need to create an
| | 05:32 | Enumerable class that doesn't already exist.
| | 05:35 | Otherwise, most times, you would
just use an array like we did here.
| | 05:39 | We don't need to go that extra step.
| | 05:40 | I did it just to make the point so that
you could see how easy it is to mix in
| | 05:45 | modules that give your
classes lots of extra functionality.
| | Collapse this transcript |
|
|
8. Working with FilesInput/output basics| 00:00 | In this chapter, we are going to learn
to work with files and directories in
| | 00:03 | Ruby, and I think it will be helpful
if we start up that discussion by first
| | 00:06 | taking a look at the basics of input and output.
| | 00:09 | Frequently, you'll see input and
output abbreviated as simply I/O. So if you
| | 00:13 | hear me say I/O, that's what I am
referring to it as input and output.
| | 00:16 | And what we were talking about is input into
a Ruby program and output from that program.
| | 00:21 | We've been using some of the
basic Ruby output for some time now.
| | 00:25 | We've been using both the puts and
print, and we have seen how both of those
| | 00:29 | work that's basic output, and so that
our program can put something out to
| | 00:34 | either the command line or to irb.
| | 00:36 | Now input, we haven't really seen yet.
| | 00:39 | We've been running a file, running
our program, but that's not really input
| | 00:42 | that's the program itself.
| | 00:44 | Even in irb where we were typing
things into the command line, that still is
| | 00:47 | sort of writing the Ruby code itself.
| | 00:50 | With input, what we really mean is
getting information into the program.
| | 00:54 | So instead of putting information
out of the program, we'll use gets to
| | 00:59 | get information back.
| | 01:01 | Let's try it on the command
line and see how it works.
| | 01:02 | So I am in my command line, I am going
to open up irb, I'll put simple prompt,
| | 01:09 | and let's try out, gets.
| | 01:11 | So if we just simply say
gets, by itself, just gets.
| | 01:16 | We don't get anything back. It just waits.
| | 01:19 | It's waiting for us to give us some input.
| | 01:21 | So let's type in Hello, and it returns
the return value of gets is whatever I
| | 01:29 | typed and then a liner turned at the end,
because I did type a return at the end
| | 01:32 | but it knew that was the ending of gets
that's how it knew we were done getting
| | 01:36 | input, and it also put
that in that string there.
| | 01:39 | So what we want to do is catch that value.
| | 01:42 | So the easiest way to do that is
just to assign into a variable.
| | 01:45 | So let's say input equals gets.
| | 01:48 | All right, it waits, Hello, and now, the
value of input is equal to that user input.
| | 01:55 | And then most of the time, we
don't want this line ending there.
| | 01:58 | It just gets in our way.
| | 02:00 | So there is a really easy way to get rid of it.
| | 02:02 | Ruby has something called the chomp
method, and we can apply it to any string.
| | 02:06 | So let's say that I have a string
and say this is a test of chomp.
| | 02:11 | I am going to put a line return
at the end inside double quotes.
| | 02:17 | So it is an actual line return
there and then I am going to apply
| | 02:20 | chomp, c-h-o-m-p to it.
| | 02:23 | And it returns the string
without the line ending.
| | 02:26 | Now if the line ending had been an r
instead or if it had been \r\in, those are
| | 02:33 | the variations on line endings that
different operating systems might use.
| | 02:37 | They all still get chopped off at the end.
| | 02:39 | That's what chomp does.
| | 02:40 | chomp will remove the line
ending if it's the last character.
| | 02:44 | If it's somewhere in this string, it
leaves it alone, only the last character.
| | 02:49 | It also has another version which is chop.
| | 02:52 | Let me just show you chop.
| | 02:54 | It does the exact same thing,
but the difference was chop.
| | 02:57 | Let me show you this, is if I say
Hello.chop, chop always removes the last
| | 03:03 | character, whether it's a line return or not.
| | 03:06 | So chomp is a little bit safer.
| | 03:08 | So typically, we are going to want to
use chomp and the way we would do it is
| | 03:11 | just to say input equals
gets, and just right away.
| | 03:14 | As soon as that value comes
back, chop off the end of it.
| | 03:17 | So there it is, the input comes back.
| | 03:19 | Let's say This is my input. This is my input.
| | 03:23 | So I get a clean string that's ready to use.
| | 03:27 | Now that demonstrates it in irb.
| | 03:29 | Let's just quit out of irb
and I'll clear that screen.
| | 03:32 | Let's look at it inside a file.
| | 03:35 | So I have got a file here in my
ruby_sandbox called input_output.
| | 03:38 | It will be in your exercise files or
you can pause the movie and copy it down,
| | 03:42 | but it's very simple.
| | 03:43 | All I am doing is that same input
equals gets chomp and I have got some
| | 03:47 | reminders up here as to what those do.
| | 03:49 | We've already seen print and puts but I
have reminded you, what each of those does.
| | 03:53 | Print doesn't put a line return,
puts does put a line return at the end.
| | 03:57 | So we are going to get some input and
then we are going to output it back.
| | 04:00 | And then the last example I have got
it is just that we can use gets inside a
| | 04:04 | loop, if we want to get multiple feedback.
| | 04:07 | And so I have got a loop here that
basically waits for me to say quit and when I
| | 04:11 | say quit, then it access the loop, but
until then, it just keeps getting user
| | 04:15 | input, and then turning around
and outputting that same value.
| | 04:19 | Let's try running this program.
| | 04:21 | So I'll just switch back to my command line.
| | 04:23 | Notice that I am already in my ruby_
sandbox, ruby input_output.rb. So there it is.
| | 04:30 | I ran the program and the first
thing it does is it does the gets.
| | 04:33 | So it's waiting for me to
type something. Hello there.
| | 04:37 | You just told me: Hello there..
| | 04:39 | Notice I have extra period there that's
not great programming, I added a period
| | 04:42 | in my code and since I had a
period here already, it doubled it.
| | 04:46 | But now I have got this prompt, so
that was something I did here with print.
| | 04:50 | So we are getting that prompt now, and
now it's waiting for me to type things.
| | 04:53 | So I can say Hello, Again, And again
and it just keeps repeating to me until
| | 05:02 | finally, I type the magic word, quit.
| | 05:05 | And then it gets that input, it outputs
quit, because that's still part of that loop.
| | 05:11 | After it gets the result and outputs it,
but then when it goes through the loop
| | 05:14 | the next time, result is equal to quit.
| | 05:17 | So it access the loop and just puts the goodbye.
| | 05:19 | So that's really all there is to user
input, but it turns out to be a very
| | 05:22 | powerful tool even though it's a very
simple, because now we have the ability to
| | 05:26 | run a program and our user can interact with it.
| | 05:29 | It can be an interactive program.
| | 05:30 | It can ask questions of the user, the
user can input their choices, they can
| | 05:34 | select from menu items, all sorts of things
and we can run Ruby code based on that input.
| | 05:39 | So now that we understand the basics of
input and output, why is that important
| | 05:44 | for learning to work with files and directories?
| | 05:46 | Well, the reason why, because files
are just a type of input and output.
| | 05:50 | We are inputting things when we read
from the file or outputting things when
| | 05:54 | we write to a file.
| | 05:56 | So it's just input and output still.
| | 05:57 | In fact, there's a Ruby class that's
called IO and it's an input/output class
| | 06:03 | that handles the basics of input and output.
| | 06:05 | And it handles various
forms of input and output.
| | 06:07 | We can send things across Internet
connection and things like, but its main
| | 06:11 | star, its primary subclass is file.
| | 06:15 | And that's what we will be working
with next is the file class, and we'll see
| | 06:18 | how we can apply these I/O
basics that we just learned.
| | 06:21 | puts, print, gets, chomps, those will
all be applicable to working with files.
| | Collapse this transcript |
| File system basics| 00:00 | In this movie, we are going to take a
look at some of the basic things you need
| | 00:02 | to know about working with the file system.
| | 00:04 | Now the real basics I am
assuming that everyone knows.
| | 00:07 | We have files on our hard drive,
they're grouped into different folders, and we
| | 00:11 | can navigate through those folders to
find the files we want, and in the same
| | 00:15 | way, we can do that from the command
line, we can also do that inside our Ruby
| | 00:20 | code in order for Ruby to
be able to find those files.
| | 00:23 | But there are couple of pitfalls that
we need to watch out for, and that's what
| | 00:26 | I want really cover in this movie.
| | 00:28 | And they are especially tricky,
because they're different on
| | 00:31 | different platforms.
| | 00:32 | Its cross-platform issues that we have,
and the first pitfall is with the file
| | 00:36 | path separators, and the
second is with file permissions.
| | 00:40 | With file path separators, it's a
pitfall, because each of the platforms,
| | 00:44 | Windows on one hand and Unix-based
platforms like Linux and Mac OS X, on
| | 00:49 | the other hand, use different separators
between the folder names that lead to a file.
| | 00:55 | So the separators of the path,
the path to the file are different.
| | 01:00 | On Unix, it's going to be a forward
slash, on Windows it's a backward slash.
| | 01:05 | And you may already know this
from working on the command line.
| | 01:07 | So which one of these do we use in our
Ruby code, because we want our Ruby code
| | 01:11 | to be cross-platform.
| | 01:12 | We want it to be able to run in both places.
| | 01:14 | The answer is that Ruby does a really
good job of allowing you to always just
| | 01:19 | use the forward slash.
| | 01:21 | So you can use the forward slash, and
even if you're on a Windows machine,
| | 01:24 | everything should work fine.
| | 01:26 | You don't want to ever use the backslash,
because that probably will not work on
| | 01:31 | a Unix-based machine.
| | 01:33 | So forward slash is the better of the
two, but there's an even better more
| | 01:36 | professional way to handle it.
| | 01:38 | And that's by using the file class.
| | 01:40 | The file class has a class method
called join and all that join does is take a
| | 01:45 | series of strings and join them
together with the appropriate separator.
| | 01:49 | So on Unix, we get the forward slash
and on Windows, we get the back slash.
| | 01:54 | Now if you are on a Windows machine,
and File.join gives you forward
| | 01:57 | slashes, don't panic.
| | 01:59 | File.join will take care of it.
| | 02:00 | It will make sure that it gives you
something that your machine can handle.
| | 02:03 | So if you got forward slashes that
means your machine was able to handle
| | 02:07 | the forward slashes.
| | 02:08 | Now the second issue is file permissions,
and file permissions is just a general
| | 02:12 | problem that sometimes jumps up and
bites you that you need to know about.
| | 02:17 | It's made even trickier by the fact
that the way we handle it is different
| | 02:20 | depending on whether we are on Unix or Windows.
| | 02:22 | Every file on your computer
has an owner of that file.
| | 02:26 | Chances are that owner is
you if it's a file you created.
| | 02:29 | And it also has permissions that say who
can read the file, who can write to the
| | 02:33 | file, and if it's a program
who can execute the file as well.
| | 02:37 | The default behavior is going to be
the most files on your local computer are
| | 02:42 | owned by you and accessible by you.
| | 02:44 | So it's not something you
have to worry about a whole lot.
| | 02:46 | Now I know there are exceptions, but
most text files that you might have on your
| | 02:50 | hard drive or something
that you could work with.
| | 02:52 | Now if you are on a network, then
there's probably a lot of files that you
| | 02:55 | are not allowed to touch, a lot of things
that you are not allowed to have access to.
| | 02:59 | So if we are going to run a program
in a network environment, it would be
| | 03:02 | something we would have to look into further.
| | 03:04 | So I am going to give you some jumping off
points, if you did want to look into it further.
| | 03:08 | If you're using Unix, Linux, or Mac OS X,
then you would want to look at chmod
| | 03:14 | as the command to allow you to change
the permissions for a file, and chown
| | 03:19 | would allow you to change the owner.
| | 03:21 | Those are just some very basics Unix
commands, they also exist in Ruby, and
| | 03:25 | there are some of Ruby methods that
allow us to do chmod and chown as well.
| | 03:30 | Now if you're on a Windows machine
though, chmod and chown aren't going to
| | 03:33 | be much use to you, because Windows has a
different permissions model than Unix does.
| | 03:38 | Instead, you are going to manage those
files through the Properties/ Security tabs.
| | 03:43 | So you click on Properties, then on the
Security tab and you can change who the
| | 03:47 | owner and the permissions are for the file.
| | 03:49 | So I know that's not concrete
solutions for how you would actually go about
| | 03:53 | solving permissions problems, but the
main thing is just to know that they
| | 03:56 | exist, that there are permissions that
would keep you from being able to write
| | 03:59 | to a file, or keep you from
being able to read from a file.
| | 04:03 | But again, with most files that are
easily accessible to you on your computer,
| | 04:06 | you're going to have access to and
you're going to have permissions for.
| | Collapse this transcript |
| File paths| 00:00 | Now that we've seen how we can use Ruby
to get the correct file path separators,
| | 00:05 | we need to understand how we
can get meaningful Files Paths.
| | 00:07 | How we can locate the files that we
either want to read from or write to.
| | 00:11 | There are two ways that we can specify the path.
| | 00:15 | The first is using an Absolute path.
| | 00:17 | The Absolute path is the path from the
root of the hard drive, from the very
| | 00:21 | beginning, how do we locate that file?
| | 00:23 | It's a path through the folders that
would take, that we would have to open up
| | 00:27 | till we got to that file.
| | 00:29 | And we know that it's an Absolute path,
because it begins with a forward slash
| | 00:33 | and that lets us know starting at the beginning.
| | 00:36 | The second type of path is a Relative
path and that's a path from where we are
| | 00:40 | right now, how do we get there?
| | 00:42 | We don't care about going back to the beginning.
| | 00:45 | We say from the current position what
folders do we need to either open up or
| | 00:50 | what parent directories do we
need to jump backwards into?
| | 00:53 | So you will see there in the Relative
path example I have got, I have got ..
| | 00:57 | that's when we want to move to a parent
directory, move back one directory into
| | 01:01 | the directory above us, and then a
single . is the current directory.
| | 01:05 | That's the directory we are in right now.
| | 01:07 | So if we are going to use a Relative path,
we need to know where we are, when we
| | 01:11 | are running one of our Ruby programs.
| | 01:14 | And Ruby gives us a variable that lets
us know that, and it's _File_ and there's
| | 01:18 | actually two underscores on
either side of capitalized word File.
| | 01:22 | And it's a special variable name that
refers to the file that were in right now.
| | 01:26 | So that's actually the File
where these characters are typed.
| | 01:30 | Now the File will just return
the name of that file to us.
| | 01:34 | If we want to actually find out where
that file is, we will need to use a method
| | 01:39 | on the file class, which is expand_
path and that says tell me what the full
| | 01:43 | path, the Absolute path is to get to this file.
| | 01:47 | Now while this works great for finding
the file that we are in right now, if we
| | 01:50 | want to find a different file, it's
going to be much more useful if we start by
| | 01:55 | using this Files directory and we
do that with the dirname method.
| | 01:59 | So dirname will tell us what directory
is this file in and we can then use that
| | 02:04 | as a starting point in our
navigation, either to go deeper into other
| | 02:08 | directories or back into a parent directory.
| | 02:10 | Let's take a look at some
code to see how it all works.
| | 02:14 | Inside my ruby_sandbox and in
the Exercise Files, I have a file
| | 02:17 | called file_location.rb.
| | 02:20 | You can pause the movie if
you want to copy this down.
| | 02:22 | At the top I have Absolute paths.
| | 02:25 | To begin with, I have just got a simple string.
| | 02:27 | That's all this is.
| | 02:28 | It's a string using forward slashes.
| | 02:30 | Even on Windows this will
probably work as a file path.
| | 02:34 | But the much better way to do it and
what I am going to recommend to you is that
| | 02:37 | you use File.join instead.
| | 02:39 | That's really going to ensure that
we have that platform independence.
| | 02:42 | And what we are asking File.join to do
is to build up that same string for us by
| | 02:47 | appending those together.
| | 02:48 | If we want it to be an Absolute path, the
first item just needs to be an empty string.
| | 02:53 | So with an empty string at the
beginning, it will say okay, this is from the
| | 02:55 | root Users, Kevin, Desktop, ruby_sandbox.
| | 02:59 | Now you may have noticed the problem
with Absolute paths which is that you
| | 03:03 | probably don't have this same
directory structure on your computer.
| | 03:07 | For example, you probably don't have a
folder called Kevin, unless your name
| | 03:10 | happens to be Kevin too.
| | 03:12 | So this doesn't make for great code.
| | 03:13 | If I am going to write something you
can't bring it on your computer and run it
| | 03:17 | if it's going to ask for this Absolute path.
| | 03:20 | Instead it's much better to use Relative paths.
| | 03:24 | The first thing we'll see is what the
value of that File variable actually is.
| | 03:28 | That's this current file File_location.rb.
| | 03:32 | That's what it's going to return
to you is the name of that file.
| | 03:34 | If we want to find out where
that file is, we use expand_path.
| | 03:38 | Now this is an Absolute path, but this
is an Absolute path it's generated at the
| | 03:43 | time it's being run, okay?
| | 03:45 | We are asking Ruby to calculate that for us.
| | 03:47 | So if you've got it on your hard drive,
you will have whatever your hard drive
| | 03:51 | structure is, whatever
path it takes to get to it.
| | 03:54 | It will not depend on you
having something like what I have.
| | 03:56 | So it's a much better way to do it.
| | 03:58 | This is the way to do Absolute paths,
to take a File or Relative path and then
| | 04:02 | get the Absolute path from there.
| | 04:04 | It's going to be much easier to
navigate, if we start out by using dirname,
| | 04:07 | so we will just take a look at what that value
is, and then finally let's put it all together.
| | 04:12 | We have got File.join, we have got
the current file, we are taking it's
| | 04:15 | directory and then I am backing up a
directory into the parent directory, which
| | 04:19 | in my case is going to be the Desktop.
| | 04:21 | And then I am going into another folder
which I have another folder here called
| | 04:24 | Exercise Files, so that's what I am going into.
| | 04:27 | I used it partly so that I could show
you what happens when you have a space
| | 04:31 | in the name of a file.
| | 04:32 | I've escaped it with the slash and very
important I've put it inside double quotes.
| | 04:39 | So if you have a file with a space in
the name, you want to take those two extra
| | 04:42 | steps, escape the space with the
backslash and put it in double quotes.
| | 04:46 | Putting it in single quotes won't
let this escape do its job, right?
| | 04:50 | Remember that about double quotes.
| | 04:51 | So when we put all of this together
that will allow us to navigate in that
| | 04:54 | Exercise Files folder and then from
there we presumably would want to load up
| | 04:59 | some file which I'm not doing it.
| | 05:01 | Right now we are just going to output
the string that's generated by this.
| | 05:03 | So let's save that and let's just go to
our command line and let's try running it.
| | 05:08 | I am in my ruby_sandbox already, so I
can just type ruby file_ location.rb.
| | 05:13 | First thing we get back is just simply a string.
| | 05:16 | Now we get the File.join that's
building that string up for us.
| | 05:20 | If you are on Windows, you
may have gotten back slashes.
| | 05:22 | If you got forward slashes, don't worry.
| | 05:24 | It means Ruby thought that you
could handle the forward slashes.
| | 05:27 | And then we have got the name of the file.
| | 05:29 | That's just the results of that file variable.
| | 05:32 | Then we asked it to expand path on that,
so that's the full path to get to the file.
| | 05:37 | When we asked it to give that file's
directory name, it said, well it's this
| | 05:41 | directory, because it was able to say you
are in the ruby_sandbox so it's this directory.
| | 05:45 | That's just a single dot.
| | 05:48 | If we want to get to Exercise Files
from here, we would go . which is the
| | 05:52 | current directory, back up a
directory and then go into Exercise Files.
| | 05:56 | Now let me just show you if we back up
a directory into the Desktop, I can now
| | 06:02 | run ruby ruby_ sandbox/file_location.rb
that's the full path to get to the Ruby file.
| | 06:08 | Now when I run it, it says
the directory is ruby_sandbox.
| | 06:12 | That's how we would get there from the
Desktop, you would go into ruby_sandbox
| | 06:16 | and then we would be in the right place.
| | 06:18 | Now for getting the Exercise Files it
says well you go into the ruby_sandbox,
| | 06:23 | then you back up one, then
you go into the Exercise Files.
| | 06:25 | It's not very efficient sometimes, but it has
been the net effect that we are looking for.
| | 06:29 | And we could of course apply expand_
path on that and it would give us the
| | 06:34 | Absolute path to those Exercise Files.
| | 06:36 | It would stop being Relative.
| | 06:38 | Now having these tools on how to
work with File Paths, it's going to be
| | 06:41 | essential for being able to find the
files we want, so that we can be able to
| | 06:45 | read and write from them, and that's
what we are going to start doing next.
| | Collapse this transcript |
| Accessing files| 00:00 | Now that we have talked about the
basics of working with the file system, and
| | 00:03 | we've seen how we can create paths to
the files that we want to work with, it's
| | 00:06 | time to see how we actually
go about accessing those files.
| | 00:10 | How do you open them up for reading and writing?
| | 00:13 | There are two different ways that we can do
it, and we'll take a look at both of them.
| | 00:16 | The first is with File.new
and the second one is File.open.
| | 00:20 | Let's look at File.new in irb.
| | 00:23 | So I will open up a new irb session
with simple-prompt, and notice that I am
| | 00:27 | inside my ruby_sandbox.
| | 00:29 | That's important, because
that's where things will be saved.
| | 00:32 | That's where my files will go.
| | 00:34 | The first approach, File.new, is
instantiating a new file object, like you would think.
| | 00:39 | So we want to assign that to a
variable, just like we normally do when we
| | 00:42 | instantiate an object.
| | 00:44 | File.new wants two arguments.
| | 00:46 | The first is the filename that we
either want to read from or write to.
| | 00:50 | We are going to create a
new file and write to it.
| | 00:52 | I am going to call it irb_testfile.txt.
| | 00:58 | That will be the name of
the file that it will create.
| | 01:00 | The second argument is going to be
the mode that we want to open it in.
| | 01:04 | We are going to use write mode to
start with, which is just to say w. We will
| | 01:09 | talk more about modes in a minute, w
is for write, r is for read. That's it.
| | 01:14 | Now we've created this new file object.
| | 01:16 | Now, take a look, all we did
was instantiate it, but look here.
| | 01:21 | It actually created the file for us.
| | 01:23 | It's in my ruby_sandbox.
| | 01:25 | So the file exists at the same time
as this object exists, because that
| | 01:30 | object is the file. That's what it is.
| | 01:32 | It's in the file system.
| | 01:34 | It's not like Microsoft Word, where you
write a document and it doesn't actually
| | 01:38 | exist in the file system until you hit Save.
| | 01:41 | At this point we've
instantiated a file, an actual file.
| | 01:46 | Now, that file is open for us to
write to, in the same way we might have a
| | 01:51 | document open in a word processor.
| | 01:52 | So we're now able to write to it, and
when we are done, what we want to say is
| | 01:56 | file.close, and you want to make
sure that you always close your files.
| | 02:00 | There are two main reasons.
| | 02:01 | One is it makes sure that you don't
accidentally write to the file when you don't mean to.
| | 02:05 | And the second reason is because it
allows Ruby to free up those resources that
| | 02:09 | it was using to hold that file open.
| | 02:11 | So you want to be a good citizen
and always close up those files.
| | 02:14 | Now, we didn't write anything to this
file, we just opened it for writing and
| | 02:18 | then closed it again.
| | 02:19 | We will see how to write to it in a minute.
| | 02:20 | Now let's look at the second way we
could do it with open, but let's do that
| | 02:23 | from an actual file instead of from irb.
| | 02:26 | I am just going to type quit, and
let's jump back over to the sandbox.
| | 02:30 | I have a file here in the
Exercise Files called accessing_files.rb.
| | 02:35 | If you open that up, you will see its
got the same thing we just did here for
| | 02:38 | instantiating a file object.
| | 02:40 | It has a different name, so
this will create a new file.
| | 02:42 | Then the second way we can
access a file is using open.
| | 02:47 | It works very much the same way, but
instead of instantiating a file object, we
| | 02:52 | just open a file and then
pass it a block of instructions.
| | 02:56 | That's just a code block.
| | 02:58 | We do whatever instructions are in
there, and at the end it closes it for us.
| | 03:02 | So we never have to instantiate it.
| | 03:03 | We don't have to hang on to this variable.
| | 03:06 | We don't have to remember to
close it. It does it for us.
| | 03:08 | For that reason I find this
works best most of the time.
| | 03:12 | Use open instead of new, because it
does close it for you, you don't have
| | 03:16 | to remember to do it.
| | 03:17 | And then it's also nice and clear, all
the things you want to put in that file
| | 03:21 | are just statements that are right here,
or everything you want to do when you
| | 03:24 | read back in from a file
is a statement right here.
| | 03:26 | Notice that we are using read this time.
| | 03:29 | So we can go ahead and run it.
| | 03:30 | Let's go ahead and just do that.
| | 03:32 | I will open up the command
line and we will just type ruby
| | 03:36 | accessing_files.rb, and it runs it.
| | 03:39 | Now, I don't get anything back,
but it did what I asked it to.
| | 03:44 | It did create file1.txt.
| | 03:46 | It opened it for writing and then it
closed it, then it opened it up for reading
| | 03:50 | and then it closed it again.
| | 03:51 | Before we move on to see how we can
actually write information and read
| | 03:55 | information from it, let's
take a look at those file modes.
| | 03:59 | There are six main file access modes
that you are going to want to consider.
| | 04:02 | There is r, which is read from the start,
and for that the file must already exist.
| | 04:07 | There is w, which writes from the start.
| | 04:10 | If the file doesn't exist, it will create it.
| | 04:13 | But if it does exist, it will wipe it clean.
| | 04:16 | It will truncate it, so that there is nothing
in it, and then start writing at the beginning.
| | 04:20 | So you have to be careful, w is a little
bit destructive if the file already exists.
| | 04:24 | The third is append, and that
lets us append to the end of a file.
| | 04:28 | That's really useful if let's say we
have a log file and we want to keep a
| | 04:32 | log of the latest action that happened,
maybe it was an order that came in or something.
| | 04:36 | We can just simply open up a file,
append the new information to the end, and
| | 04:40 | then close the file again.
| | 04:42 | Now, I noted that w is destructive,
and that it really wipes the file clean.
| | 04:46 | What if we want to read and write from a
file but not erase everything that was there?
| | 04:50 | Well, for that we need to use r+, which
you will see over in the right column.
| | 04:54 | That lets us both read and write.
| | 04:56 | It does not destructively
wipe out the document first.
| | 05:00 | It just lets us both read and write
and it puts us at the beginning of the
| | 05:04 | document, ready to start.
| | 05:05 | W+ lets us both read and write, but it
does that same destructive truncating, so
| | 05:11 | we don't use it that often.
| | 05:13 | And then append+ does the same thing.
| | 05:16 | It puts us at the end of the document
and will let us both read and write, and
| | 05:20 | we'll see how we can move around
in the document a little later on.
| | 05:22 | Now, most of the time what you are
going to want are r, w, a, and r+.
| | 05:29 | a is for the special case where you
want to just append something at the end.
| | 05:31 | W is most useful when you want
to start a brand new document.
| | 05:36 | And 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:00 | Now that we have seen how we can
access files, and how we can open them up
| | 00:04 | to enable us to write to them, let's see
how we can actually write data to the file.
| | 00:08 | Fortunately, because in the very first
movie of this chapter we saw how to do
| | 00:10 | the basics of input and output,
it's going to be super simple.
| | 00:13 | I want to start out by opening up the irb_
testfile.txt that we created in the last movie.
| | 00:19 | It should just be a blank file.
| | 00:21 | But let's type something
in there, This is a test.
| | 00:24 | You can type anything you want.
| | 00:26 | Save it, close it up, now
it has some text in there.
| | 00:29 | Now I am going to go into irb.
| | 00:31 | Notice I am already in my ruby_
sandbox where that file is located,
| | 00:34 | simple-prompt, and I am going to just
instantiate a new file, File.new, and it
| | 00:43 | will be that file name, irb_testfile.txt.
| | 00:47 | You want to make sure you type the name
correctly otherwise it will create a new file.
| | 00:52 | What we want to do instead is open that
file and actually overwrite what's there.
| | 00:56 | That's what I want you to see.
| | 00:57 | So I've instantiated it now.
| | 00:59 | Let's go take a look.
| | 01:01 | Open up irb_testfile.txt and
you'll find that its empty.
| | 01:06 | So at the moment that we
instantiate it, it wipes it clean.
| | 01:10 | Now let's see how we can
actually write data to this file.
| | 01:13 | Before when we wanted to
output data, we used puts.
| | 01:16 | Well, we can use the same thing here,
we just do it as a instance method,
| | 01:20 | file.puts, and then whatever we
want it to put, let's say abcd.
| | 01:26 | Now let's take a look.
| | 01:27 | It returned nil to us, just like normal.
| | 01:29 | Let's go back over and look at
the file again. It's not there.
| | 01:32 | So whenever we write something to a file,
it waits for us to actually close the
| | 01:36 | file before it writes all of that data.
| | 01:39 | That makes sense, I mean every time
that it's going to write a little tiny bit
| | 01:43 | of data, it would have to
access the hard drive again.
| | 01:47 | So if we were going to output let's say
a thousand rows that we were composing,
| | 01:51 | then it would have to access
the hard drive a thousand times.
| | 01:54 | It's much better to assemble all of that and
then write to the hard drive just one time.
| | 01:59 | So let's go ahead and say file.close,
just so we can see that. Let's close it.
| | 02:04 | Open up irb_testfile.txt, and
there we go, you see it's there.
| | 02:06 | So now let's just go back
and open the file again.
| | 02:10 | We are going to overwrite what was
there, so we are going to need to
| | 02:13 | do file.puts "abcd".
| | 02:16 | Now, as you might guess, we also
have file.print available to us.
| | 02:20 | So we have efgh that we can print, and
the difference is that print doesn't put
| | 02:25 | a line return like puts does.
| | 02:27 | There are also two others that are
basically the same as print, with just subtle
| | 02:30 | differences, file.write "ijkl", and
that will do the same thing as print.
| | 02:37 | It will write to the file, but notice
that it returned something besides nil.
| | 02:42 | Instead, it actually returns the
number of characters that it wrote.
| | 02:47 | So if you feel more comfortable using
write instead of print, that's fine.
| | 02:51 | Either one works the exact same way.
| | 02:53 | Then last of all, we can append to the
file, to the file object, we can use the
| | 02:57 | append method and append mnop to it.
| | 03:00 | The only difference is that it
will return the file object to us.
| | 03:04 | Otherwise it's essentially
the same as print and write.
| | 03:07 | So last of all, let's just close this up.
| | 03:09 | We can go take a look to see what's
there, irb_testfile.txt, and it's exactly
| | 03:15 | what you would expect.
| | 03:17 | We had also created this file1.txt.
| | 03:20 | I am just going to open up accessing_
files.rb, because I've written something in
| | 03:23 | here that we can use to populate that.
| | 03:25 | So again, we are just going to open
up that file for writing, and then I am
| | 03:29 | going to put in Ruby
programming with a line return.
| | 03:33 | I don't have to use puts to get a line
return, I can always just put my own as
| | 03:36 | long as I put it in double quotes.
| | 03:39 | So use this line return in double quotes,
and then it will return the line that
| | 03:44 | I am doing the write and the fun
and close it, exact same thing.
| | 03:46 | Let's just open this up, we will quit
out of irb, and instead we will run the
| | 03:52 | file, accessing_ files.rb.
| | 03:55 | It doesn't return anything to us.
| | 03:57 | But if we go and we take a look over
here, we will see that file1.txt does have
| | 04:03 | those three lines in it.
| | 04:04 | That's all there is to
being able to write to files.
| | Collapse this transcript |
| Reading from files| 00:00 | Now that we know how to write data to
files, it's time to see how to read data
| | 00:04 | back from files, and
fortunately it's just as easy.
| | 00:08 | In the last movie, I wrote the
irbtestfile.txt and I just put the alphabet from
| | 00:13 | a to p with a line break after the d.
So that's what we are looking at.
| | 00:16 | That's the text we're going to
be working with. I'll close that up.
| | 00:19 | Let's go back into irb, notice I'm
in my ruby_sandbox, simple-prompt.
| | 00:26 | So let's go ahead and
just instantiate a new file.
| | 00:28 | I am going to use the instantiation method
because I want to step through the process.
| | 00:32 | I don't want to execute the
whole block of code at one time.
| | 00:35 | irbttestfile.txt and then read.
| | 00:42 | We are going to read back
from this time, not write.
| | 00:45 | Write would overwrite what we
have there; instead we want to read.
| | 00:48 | So now, if we used puts to put
information into the file, then guess what?
| | 00:53 | We use gets to get a line back out of the
file and notice it includes the line return.
| | 00:59 | It is in fact the mirror image of puts.
| | 01:01 | Puts a line plus a line return;
gets gets a line plus the line return.
| | 01:07 | And we've seen how we could use file.
gets.chomp, and that will return the next
| | 01:12 | line without the line return.
| | 01:13 | Let's try running file.gets.
chomp one last time now. Oh!
| | 01:19 | We get back an error, because this
time there was nothing left to get.
| | 01:23 | So we need to be careful when we
use chomp, we need to make sure we can
| | 01:27 | get something first.
| | 01:28 | When we get to the end of the file,
there is nothing there. returns nil.
| | 01:31 | Watch file.gets returns nil.
| | 01:34 | Nil can't handle chomp.
| | 01:36 | It won't chomp anything off the end of nil.
| | 01:39 | So unlike where we are getting
user input where we can just use chomp
| | 01:43 | automatically on top of the gets,
we're going to have to be a little more
| | 01:46 | careful here when we are reading from
a file and first make sure that we did
| | 01:49 | get something back.
| | 01:50 | So I am going to go ahead and just do file.
close and then let's reopen that file again.
| | 01:55 | This time though, instead of reading a
full-line, I am going to show you how we
| | 01:59 | can do to read to read back part of a line.
| | 02:03 | So we used write earlier and that wrote
something without a line return, it just
| | 02:07 | wrote a few characters and
returned the number of characters.
| | 02:11 | Well now with read we just tell it, well how many
characters do we want to read? Read 4 characters.
| | 02:16 | So there is 4.
Let's tell it to read 3.
| | 02:20 | It gave me the line return and nef.
| | 02:24 | Line returns still counts as a character.
| | 02:26 | Let's asked it to read us
another 3, ghi and so on.
| | 02:31 | So those are the two primary
ways that we can read from the file.
| | 02:33 | We can either get back a whole line or we can
get back just a certain number of characters.
| | 02:39 | Now that reads data but we have a lot of
data, if we've a lot of lines, we don't
| | 02:43 | want to do this one at a time, right?
| | 02:45 | We want to actually loop through it.
| | 02:47 | Let me show you how we
can make that kind of loop.
| | 02:48 | Let's do a file.close, be good
citizens and close up our file and then I'll
| | 02:53 | go ahead and hit Quit.
| | 02:55 | Let's switch over to accessing_files.rb.
This is the file we're working with.
| | 03:00 | We had it output 'Ruby programming
is fun' to file1.txt, we wrote that.
| | 03:05 | This will overwrite that with the same
thing again when I run it, but now I am
| | 03:10 | actually read back in using a loop.
| | 03:12 | Now notice what we've done here.
while line = file.gets, so while there is a
| | 03:18 | new line, if it returns nil, the loop exits.
| | 03:21 | So that's a good way to loop through
and get each line one after another.
| | 03:26 | Then I have applied chomp down here, not
up here. Remember that gives me a problem.
| | 03:31 | So instead we want to make sure it exists.
| | 03:32 | And then if it exists, chomp off
the end of it, reverse it and put it
| | 03:37 | inside these asterisks.
| | 03:40 | Now if you know that you're going to
loop through each and every line and that's
| | 03:44 | really what you're after, then an
easier way to do is with each line.
| | 03:48 | So we just open up the file and then
we say, all right, file, go through
| | 03:51 | each one of your lines and taking that line
in my code block, what do I want to do with it?
| | 03:57 | And here I am just going to upcase it.
| | 03:59 | So let's save it, let's see how this works.
| | 04:01 | We're going to the Terminal, I am in my
ruby_sandbox, so I just have to do ruby
| | 04:05 | accessing_files.rb and there we go.
| | 04:08 | The first one uses a gets
loop to go through each one.
| | 04:12 | The second one just uses each
line to go through and process it.
| | 04:15 | Essentially, they both do the same thing.
| | 04:17 | Each line just might be a
little easier for you to write.
| | Collapse this transcript |
| File pointer| 00:00 | In this movie, I want to explain what
the file pointer is and show you how
| | 00:03 | you can manipulate it.
| | 00:04 | The file pointer works a lot like
the cursor does inside your word
| | 00:07 | processing program.
| | 00:09 | You can use the arrows to move around
the text until you find the position that
| | 00:12 | you want and then you can start
typing and it'll start typing at that spot.
| | 00:16 | Well the file pointer works the
same way with a couple of differences.
| | 00:19 | First of all, if the file pointer is at
a certain spot, it doesn't insert text.
| | 00:24 | It overwrites text.
| | 00:25 | So be careful about that.
| | 00:27 | The second difference is that we use
the file pointer not just for writing to
| | 00:30 | files but also for reading from files.
| | 00:33 | And you may have noticed that in the
last movie, when we're reading back data
| | 00:36 | from a file, if we asked it to give us
5 characters, then when we asked it for
| | 00:40 | another five, it started after
those first five. It kept track.
| | 00:44 | It moved the pointer along to keep
track of the fact that it had already given
| | 00:48 | us 5 characters and it
didn't give them to us again.
| | 00:50 | And if we did a gets then it advanced
the file pointer go to the beginning of
| | 00:54 | the next line, so that the next
gets would return the next line.
| | 00:57 | Let's see how we can find out the
location of the file pointer and also move it
| | 01:01 | to different locations.
| | 01:03 | I am going to be using irb_
testfile.txt that we created earlier.
| | 01:06 | It's a real simple text file, you can
use any bit of text that you want.
| | 01:09 | Mine is just letters a through p with a
line return after the d. I am going to open
| | 01:14 | up my command line, I will do irb simple-
prompt and notice I am already in my ruby_sandbox.
| | 01:21 | From there I'll instantiate a new
file, File.new irb_testfile.txt, and
| | 01:29 | we'll open it in r+ mode.
| | 01:31 | Remember we are going to read from it
and also write from it and r+ puts us at
| | 01:35 | the beginning of the file.
| | 01:37 | So we can find out that we are at the
beginning of the file by finding its position.
| | 01:40 | file.pos and that's how
we find out the current position.
| | 01:44 | Just like an array it starts counting with zero.
| | 01:45 | And if we now say file.read(3), that will
return three characters or three bytes to us, abc.
| | 01:54 | Now if we go up, file.pos, we are at 3 now.
| | 01:57 | It's moved the pointer along to 3
and if we do another read,
| | 02:00 | the same thing would happen.
| | 02:02 | Let's do a file.gets now.
| | 02:05 | Notice that while we've been casually
saying that gets returns a line to us,
| | 02:10 | it doesn't actually.
| | 02:12 | What it does is it returns everything
from the current file pointer position all
| | 02:16 | the way till it gets to the end of the line.
| | 02:18 | So if we change the position to move
over one at the beginning and then do the gets,
| | 02:22 | every single line would
be missing its first character.
| | 02:26 | Now if we ask for a file.pos, you'll
notice that position is not 0 because
| | 02:31 | we hit the new line.
| | 02:32 | It just keeps on counting.
| | 02:33 | It goes to the entire document
as one long series of numbers.
| | 02:37 | It doesn't wrap around it at all.
| | 02:39 | Inside the file, it doesn't care about the
difference between the d and the line return.
| | 02:43 | Those are both considered one character.
| | 02:46 | And we can move around inside the file too.
| | 02:47 | For example, let's say file.pos= and we
can give it a position, let's say 13,
| | 02:55 | file. and let's read back 3 again, m, n, and o.
So at position 13, that's the text that's there.
| | 03:02 | Now the position moved when I did that.
| | 03:05 | Now I am at 16 because it advanced it
when I did the read operation, so just
| | 03:09 | be careful about that.
| | 03:11 | So there should be one more
letter there, file.read(10).
| | 03:16 | Let's see that file.pos is now equal to 17.
| | 03:20 | So when I did to read, it stopped at the end.
| | 03:22 | Just stopped right there at the end.
| | 03:24 | It said okay now you are at the end
and we can actually say file.eof? true.
| | 03:30 | It is at the end of the file and if we
weren't at the end of the file, it would
| | 03:33 | return false of course.
| | 03:35 | Now we can write something if we want here.
| | 03:37 | Let's do file.write and let's do qrst
and we can also jump back to the beginning
| | 03:45 | of the file, we could use file.pos=0.
| | 03:48 | We know how to do that but we also can
use file.rewind and that takes us back to
| | 03:53 | the beginning as well.
| | 03:54 | I want to show you that you can use
file.pos+= if you want to go from the
| | 03:59 | current position, if you want to
move forward 6 from wherever we are.
| | 04:04 | Now we could a file.read(1). That's what I get.
| | 04:08 | I can do the same thing file.pos-=.
| | 04:11 | Let's just go back 2, file.read(2).
I should get back e and f.
| | 04:17 | So that's really all you need to know
about being able to move the file pointer
| | 04:21 | around inside the file so that you
can read and write at various spots.
| | 04:25 | Now there's too big pitfalls that I
need to caution you about though because
| | 04:29 | they can trip you up.
| | 04:30 | The first is let's do a file.rewind.
| | 04:33 | Okay now I am back at the beginning of my file.
| | 04:35 | There is something called file.lineno and that,
you may think, oh, that's the line number.
| | 04:42 | Let's do file.gets and then let's ask for
the next line number. Okay, now it's 1.
| | 04:47 | It seems to be it's returning
the line number but it's not.
| | 04:52 | Don't get tripped up by this.
| | 04:53 | It is an internal counter that gets
uses, gets and also another method called
| | 04:59 | read line and they used it to keep track of
what line they're on at the time. Let me show you.
| | 05:04 | We have done a gets now.
| | 05:05 | Let's change our position now, file.pos=0.
| | 05:08 | We'll go back to the
beginning. file.lineno, still on 1.
| | 05:14 | It has not changed.
| | 05:16 | And if I say file.gets, now
file line number is equal to 2.
| | 05:21 | Line number is just an internal
counter that keeps track of how many times
| | 05:24 | gets has been called.
| | 05:26 | It has no relationship whatsoever to
the file pointer. It has nothing to do with
| | 05:31 | the file pointer, so do not
get fooled into thinking that.
| | 05:35 | If we were to do file.rewind, there's
one slight difference between setting the
| | 05:39 | position equal to rewind,
which is position equal,
| | 05:42 | it does nothing to line number. rewind also
sets line number back to 0 at the same time.
| | 05:47 | So file.lineno is back at 0.
| | 05:49 | So what is this line number thing good for
then, if doesn't actually tell us the lines?
| | 05:53 | Well it's useful if you're just going
through and using gets over and over and
| | 05:57 | over again to know what line
you're on. Let me show you.
| | 06:00 | Let's write a real simple while line =
file.gets and let me just paste in a line
| | 06:08 | of code here so I don't have to retype it,
puts and then we'll output the line
| | 06:13 | number and then the line
and then end. So there we go.
| | 06:17 | Now we have been able to sort of prefix
every one of our lines with the line number.
| | 06:21 | That's the kind of thing that it's good for.
| | 06:23 | Now the second pitfall that you need
to watch out for is that you can set the
| | 06:26 | position beyond the end of the file.
| | 06:29 | When we were doing a read, remember it
stopped at the p. It didn't keep going
| | 06:33 | but we can set the position.
| | 06:34 | Let's say file.pos+=, and let's say 100.
| | 06:40 | So now I'm position 121 of my document
and you know that I only have the letters
| | 06:46 | a through t now, right?
| | 06:47 | You can see that in the gets that we just did.
| | 06:50 | So I definitely don't have 121.
| | 06:53 | If I do a file.read(1), it returns nil.
| | 06:57 | That's what it reads there.
| | 06:58 | There's nothing, but I can do
a file.write. Let's do xyz.
| | 07:03 | So it did successfully write it.
| | 07:05 | Let's go ahead and do this loop that
we just did up here, the gets loop.
| | 07:08 | Let's do that again and see
what we get back this time.
| | 07:11 | So let's do file.rewind, get back to
the beginning and then while line =
| | 07:16 | file.gets and I'll paste
in that same line again.
| | 07:21 | Now it looks like it worked there.
| | 07:22 | It looks like it did what we would want.
| | 07:24 | It just started writing at the end of the file.
| | 07:27 | Let's say file.close now and let's
just reopen our file one more time, file =
| | 07:35 | File.new "irb_testfile.txt" and we'll
open it in both reading-writing mode again.
| | 07:44 | file.gets, file.gets. Now look at that.
| | 07:52 | So when we did it this way,
it seemed to all work just fine.
| | 07:58 | But when I did it this way,
look what we got back.
| | 08:01 | When it wrote, it wrote a bunch of
invisible characters, almost 100 of them
| | 08:06 | because that's how far we jumped ahead.
| | 08:08 | This is the octal notation for nil.
| | 08:11 | So what it's doing is it's taking all
of those nils and converting them into
| | 08:14 | invisible characters.
| | 08:16 | In fact, let's just look here.
| | 08:17 | If we open up irb_testfile,
they look empty, right?
| | 08:21 | It looks like there's
nothing there but in fact they are.
| | 08:24 | It's being written with these real
strange characters, which can throw
| | 08:27 | things off for you.
| | 08:28 | So I want you to be really careful about
writing beyond the end of your document.
| | 08:33 | You can always rewind to the beginning
of it and then do gets until you get to
| | 08:37 | the bottom and when gets returns nil,
you'll know you're at the bottom, then you
| | 08:40 | can start writing but don't just sort
of use position to jump off into outer space
| | 08:45 | and start writing or you'll get
this kind of unpredictable behavior.
| | 08:48 | If you keep those two pitfalls in
mind though, moving around inside the
| | 08:51 | document will be really easy.
| | Collapse this transcript |
| Renaming and deleting files| 00:00 | Now that we know how to read and write
from files, let's see how we can rename
| | 00:04 | our files and delete them.
| | 00:06 | So I am going to do the renaming and
deleting from irb rather than inside a script.
| | 00:10 | Let's do simple-prompt, open up
irb, and I'll create a new file to start
| | 00:16 | out with that we can rename
and then delete when we are done.
| | 00:19 | So file equals File.new and let's
call this file_to_rename.txt and we'll go
| | 00:27 | ahead and just say we are going to write.
| | 00:29 | And while we are at it, we'll say puts
"This is a file for renaming and then deleting".
| | 00:40 | file.close.
| | 00:41 | All right, so now we've got our file there.
| | 00:43 | Let's just double-check.
| | 00:44 | Look at our sandbox, file_to_rename,
there it is in my ruby_sandbox.
| | 00:48 | You want to make sure that
where you are located is where it'll be.
| | 00:52 | So now let's see how to rename it.
| | 00:53 | It's nice and simple. We just use the
File class and call the rename class method.
| | 00:58 | So 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:09 | Since we are going to delete it next, let's
call it 'file_to_delete.txt' and that's it.
| | 01:15 | That's all there is to
being able to rename a file.
| | 01:17 | If we look here now, it's called
file_to_delete. It works really well.
| | 01:22 | Deleting works just as easily
File.delete and then now it's
| | 01:27 | called file_to_delete.txt. Here it is.
| | 01:31 | Let me take a look.
| | 01:33 | Sure enough now the file is gone.
| | 01:35 | So that's really all there is to the
syntax of being able to rename and delete files.
| | 01:39 | One thing you need to really watch out
for though is that with read and write,
| | 01:42 | we had to make sure that we had read and
write access to the file, but if we are
| | 01:46 | going to rename and delete, in addition
to having write access to the file,
| | 01:50 | we also need write permissions on the
directory that contains the files.
| | 01:54 | So you want to watch out for that.
| | 01:56 | The other question that I want to
address that sometimes comes up is what about copy,
| | 01:59 | what if we want to copy a file?
| | 02:00 | Let's create a new file again.
| | 02:03 | Let's go back up here and make a new one,
but this time we are going to call it
| | 02:06 | file_to_copy and then we'll
just go ahead and close it.
| | 02:10 | We don't need to put anything inside.
| | 02:11 | That will create the file for us.
| | 02:13 | Take a look and confirm
that it's there, file_to_copy.
| | 02:15 | So now, let's take that file and let's
say File.copy and let's try using the
| | 02:21 | same syntax as rename.
| | 02:22 | Let's do file_to_copy.txt and let's
give it a new name for the new copy.
| | 02:29 | We'll just call it copied.txt. Let's close it up.
| | 02:34 | Oops! there is no copy method on the File class.
Instead the way that we copy files is
| | 02:41 | by including one of the standard
libraries that comes with Ruby.
| | 02:45 | It ships with Ruby.
| | 02:46 | It's already there but it's not loaded up,
but we know how to load things up.
| | 02:49 | We just use, require, require and
it's going to be called fileutiles.
| | 02:57 | That's all we've to type
is require 'fileutiles'.
| | 02:59 | It comes up true, means that
it loaded in all that Ruby code.
| | 03:02 | It's just sitting there waiting to be
loaded and now we can say FileUtils.cp
| | 03:11 | for copy or copy and then let's do file
to copy.txt, and this time, let's call
| | 03:20 | it copied_file.txt.
| | 03:25 | Take a look, and sure enough, here's
my copied_file and my file_to_copy.
| | 03:29 | So that fileutils is the way
to get the copy functionality.
| | 03:33 | So in fact, let me break it
down for you a little more.
| | 03:36 | The file class gives us rename and
delete among all the other options of
| | 03:40 | course that we've seen, all the other methods
we've been looking at throughout this chapter.
| | 03:43 | But we have rename and delete there,
and unlink is a synonym for delete.
| | 03:46 | So you can use that if you would rather.
| | 03:47 | Then we have this file
utilities class that we can load in.
| | 03:50 | It's part of the Ruby standard library.
| | 03:52 | require 'fileutils' brings
it in so that we can use it.
| | 03:55 | And we have copy, move, and remove all
in there and you'll notice that the two
| | 04:00 | letter abbreviations cp, mv and rm.
If you're familiar with working with Linux in
| | 04:04 | the command line, you'll recognize those
as being the kinds of command lines you
| | 04:08 | would enter in Unix.
| | 04:10 | So that's really what File Utility is doing.
| | 04:12 | It's giving us a Ruby interface to all
those things that we normally would do
| | 04:15 | from the command line.
| | 04:16 | So we also have cd, chmod, chown, pwd,
ln, touch, make directory, remove
| | 04:22 | directory, all of those are
available to us in file utilities as well.
| | 04:25 | So it's very useful.
| | 04:26 | I wanted to caution you against using
something else that's called FTools.
| | 04:30 | That's also a part of the Ruby 1.8
standard library. You probably have it.
| | 04:35 | You can use require ftools, and what it
does is it's a module that adds a lot of
| | 04:39 | these fileutils features
to file, especially copy.
| | 04:43 | So we have copy then inside our file
class and that File.copy would work, but
| | 04:48 | it's not recommended that you use FTools.
| | 04:50 | It's better to use
FileUtils for a lot of reasons.
| | 04:53 | The biggest reason though is that it's
going to be removed from the standard
| | 04:56 | library in Ruby 1.9.
| | 04:59 | So pretend that it doesn't exist, just
ignore it. As soon as you see it, think
| | 05:02 | oh, that's not something I want to use.
File and FileUtils are going to handle
| | 05:06 | all of your file renaming,
deleting, and copying needs.
| | Collapse this transcript |
| Examining file details| 00:00 | In addition to reading, writing and
deleting files, a lot of times we want to
| | 00:04 | actually just find out some basic
information about the file and that's what
| | 00:07 | we're going to see how to do in this movie.
| | 00:08 | To demonstrate, I am going to go
into irb. Notice I am already in my
| | 00:11 | ruby_sandbox, simple-prompt.
| | 00:15 | Before we start, I am going to just
assign a variable file equal to a string and
| | 00:20 | that will be the name of the file, and
let's make this that irb_testfile.txt or
| | 00:25 | you can put any filename you want.
| | 00:27 | Any file that you know already exists.
| | 00:29 | We're just going to be checking
out information about that file.
| | 00:31 | So that's my file, I can then use the
string instead of having to type that
| | 00:35 | all out from now on.
| | 00:36 | I can just pass the variable file in.
| | 00:37 | There is a number of class methods
on the file class that let us check
| | 00:41 | out information, File.exist, for example,
very handy for finding out if a file exists.
| | 00:47 | If we want to find out whether it exist
before we try to read to it, write it,
| | 00:51 | rename it, delete it, that's very
useful and we'll use that a lot.
| | 00:54 | We also can check to see whether
it's actually a file. file, true.
| | 00:59 | Well, we say, well what's the alternative?
| | 01:01 | Well, it could be a directory.
| | 01:02 | A directory will also return true
that it exists, but then we can tell the
| | 01:06 | differences whether it's a file
or not by using file or directory.
| | 01:10 | We can also check whether it's readable, true.
| | 01:15 | Is our file writable? File.
| | 01:19 | How about executable?
| | 01:21 | Now, this would be for scripts and for
applications that have the executable
| | 01:26 | permission set, my file doesn't by default.
| | 01:28 | You can also checkout file size, File.
size(file) and that's going to return
| | 01:34 | in bytes the answer.
| | 01:36 | 124, that's the how large my file is.
| | 01:39 | Now that's the number of characters
that are in there, if you are using a
| | 01:42 | single-byte language.
| | 01:43 | So that's also really useful, and it's
especially useful for making sure that
| | 01:47 | you don't write beyond the end of the file.
| | 01:49 | Remember, we talked about that how we
could set the position beyond the end of
| | 01:52 | the file, and there were some
pitfalls that came with that.
| | 01:54 | Well, size helps us make sure
we don't go too far in the file.
| | 01:58 | We've also seen a couple already that
we'll just review, we had File.dirname
| | 02:01 | that will show the directory of the file.
| | 02:04 | So the directory is the directory I am in now,
which is ruby_sandbox while I am running irb.
| | 02:10 | We also saw File.expand_path.
| | 02:15 | So that expands to show us the full
path of where the file is located.
| | 02:18 | We have something that's sort of the
opposite of that File.basename which I've
| | 02:23 | just putted on the string.
| | 02:25 | It just returns the string to me.
| | 02:26 | That's no magic there, right?
| | 02:28 | But if I do expand the path, let's
do a File.expand_path, and let's set
| | 02:34 | that equal to full_path.
| | 02:36 | So we'll just set that equal to variable.
| | 02:38 | Now if we do File.basename on full_path,
we'll get back just the name of the file.
| | 02:46 | So it really is sort of
the reverse of expand_path.
| | 02:48 | If you want to expand it to get the
full thing, basename says just give
| | 02:51 | me what's at the end.
| | 02:52 | It's also File.extname, the extension
name, and we can call that, and it gives
| | 02:58 | us back.txt in this case.
| | 03:00 | That's useful, especially if you are
working with images when you know if it's a
| | 03:03 | JPEG or something, you can use that.
| | 03:05 | The three more that I want to show you,
and then I want to explain a little further.
| | 03:08 | We have File.atime(file), File.
mtime(file) and File.ctime(file).
| | 03:19 | So it just all three of those give
you back a time related to the file.
| | 03:22 | Let's talk about what each one
is, because it can be confusing.
| | 03:25 | File.mtime is the last
modified time and that's pretty simple
| | 03:29 | and straightforward.
| | 03:30 | It's the time the file was last written to.
| | 03:32 | File.atime is the last time it was
accessed, even when it's been read.
| | 03:37 | It lets us know whenever it's
been read from or written to.
| | 03:40 | We don't know which one happened,
unless we also look at mtime and then we
| | 03:43 | might be able to tell.
| | 03:44 | But mtime is write, atime is read or write.
| | 03:48 | ctime is the last status change time.
| | 03:52 | It's not the created time.
| | 03:53 | It confuses a lot of people.
| | 03:55 | It is not created time and people
think well, I've modified, I've accessed,
| | 03:59 | what about created?
| | 04:00 | That's because it's not possible to
find out the created time of a file.
| | 04:04 | I mean, after all what is the created time?
| | 04:06 | If I retrieve a file from a backup
copy and put it on my hard drive, was it
| | 04:10 | created at the time that it was backed
up or created on my hard drive, right?
| | 04:13 | It was the time that it was modified.
| | 04:16 | So ctime, let's talk about what it is,
is the last time that the status changed.
| | 04:20 | That means that it was read to or
written from, or any changes to owner,
| | 04:25 | group and permissions.
| | 04:26 | In general, try not to use it. Unless
what you are really trying to find out is
| | 04:30 | when the owner, group or permission is
changed, there is no reason to use it.
| | 04:34 | So just avoid it and stay away from it,
but it's definitely not created time.
| | 04:38 | That covers most of these
class methods on the file class.
| | 04:40 | But what about when we're
working on a file, right?
| | 04:43 | What if we have myfile = File.new(file),
and let's open it up for reading.
| | 04:50 | All right, so I am going to open that file up.
| | 04:52 | I am now inside the file.
| | 04:54 | Inside, I have an instance.
The instance is called myfile.
| | 04:57 | Notice that I called it myfile so it
wouldn't conflict with file that we
| | 05:00 | had already created.
| | 05:01 | You want to be careful about using this
word file too often or you'll get confused.
| | 05:04 | So I've called it myfile.
| | 05:06 | It's now an instance. Can we
called instance methods on it?
| | 05:09 | Let's try myfile.size, no.
| | 05:11 | myfile.readable, no.
| | 05:16 | Those methods don't exist as
instance methods on the file class.
| | 05:20 | However, we have something called
stat, myfile.stat, and that returns
| | 05:27 | a File::Stat object.
| | 05:30 | Class is File::Stat and you can look
inside there and you can see a lot of the
| | 05:34 | attributes that it has.
| | 05:36 | So a lot of these things are there, like size.
| | 05:38 | So we can say myfile.stat.size and find
out the size, or myfile.stat.readable.
| | 05:47 | And we can find out
whether it's readable or not.
| | 05:49 | So that's the way you do it.
| | 05:50 | From inside, you just have to make
this one extra step to call for that stat
| | 05:54 | object, and once that stat object
appears, and you have it ready for you to
| | 05:58 | work with, then you can call all those
methods as instance methods on that stat object.
| | 06:03 | Again, I find that that's especially
useful, if we need to stop and check
| | 06:06 | the size of the document to make sure that
we aren't writing past the end of the file.
| | 06:10 | And that's really all there is to it.
| | 06:11 | Let's go ahead and close up
our file, just for good measure.
| | 06:13 | Now that we know how to find
out information about our files.
| | 06:17 | It really concludes a full
understanding of how we can work with files,
| | 06:21 | but we still haven't talked about
directories, the folders that house our files.
| | 06:25 | Let's look at that next.
| | Collapse this transcript |
| Working with directories| 00:00 | Now that we understand how to work
with files in Ruby, it's important that we
| | 00:03 | also understand how to work with directories.
| | 00:05 | Because we're going to want to
navigate around directories to find our files,
| | 00:08 | and we'll want to create and delete
directories in order to organize our files.
| | 00:11 | Fortunately for us, working with
directories is very similar to working with files.
| | 00:16 | Before we go into IRB, I want to
take a look at my ruby_sandbox.
| | 00:19 | That's the directory I'll be using.
| | 00:20 | You could use any directory you
want, doesn't matter, but take note of
| | 00:23 | the contents of it.
| | 00:25 | I've got accessing_files, all
the way down to, to_do_list.
| | 00:29 | Those are the files that are in
that directory that I can see.
| | 00:31 | Now, let's switch over to the command line.
| | 00:34 | Notice that I am already inside my
ruby_sandbox. If you are on a Windows
| | 00:38 | machine, once you are in the directory
you want, you'll type dir to get a list
| | 00:41 | of the contents of the directory.
| | 00:43 | If you are on a Linux, Unix or
Mac machine, you'll type ls dash la.
| | 00:49 | Now, we can view the
full listing of these files.
| | 00:51 | I wanted to use those extra options
because I wanted to show you that there are
| | 00:55 | some files that appear above accessing_files.
| | 00:58 | Now if you don't have the
same thing as me, don't worry.
| | 01:00 | I just want you to be aware
that it's possible that you would.
| | 01:04 | .DS_Store is an invisible file.
| | 01:07 | That's what the dot tells us. It's invisible.
| | 01:09 | It means that it's
basically a configuration file.
| | 01:11 | It's not a real file that we normally
want to worry about, in the sense that we
| | 01:14 | usually work with files.
| | 01:16 | So the operating system hides it from us.
| | 01:18 | Now DS_Store happens to be a
configuration file that the Mac operating system
| | 01:22 | uses to keep track of things like the
size of the window and the position on
| | 01:26 | the screen, and that's how it keeps track of it.
| | 01:28 | It's in this little file.
| | 01:29 | Now there is a couple of others up here
though, we've got dot dot, which is the
| | 01:33 | parent of this directory, and
dot, which is this directory.
| | 01:36 | It seems kind of strange to have this
directory as an item inside this directory.
| | 01:42 | But what we're actually looking at is
the directory listing, right. It's sort of
| | 01:45 | index of items that the directory knows about.
| | 01:48 | So it knows about all the items that
are inside of it, but it also knows where
| | 01:51 | its parent directory is.
| | 01:52 | It knows what parent it belongs to,
and so it has an entry for that.
| | 01:56 | It also has an entry for itself. Why?
| | 01:59 | Because that way it can keep track
of the permissions that are on it.
| | 02:02 | So it can use that entry about itself to
keep track of information about itself.
| | 02:07 | So these items that begin with the dot
at the beginning, we'll just want to be
| | 02:10 | aware of as we are working.
| | 02:11 | We'll either want to filter them out or skip
over them or something, and get to the real files.
| | 02:16 | But those are considered
entries in the directory.
| | 02:19 | So let me just clear my screen here.
| | 02:21 | I am going to open up an irb session and
notice that I am already inside my ruby_sandbox.
| | 02:26 | That's important.
| | 02:28 | We've seen already how we can use
File.dirname and that special variable file to
| | 02:32 | find out the directory
of the file that we're in.
| | 02:34 | Well, we are not in a file, we are
inside irb, but irb still returns the
| | 02:38 | directory that we're in, which is
ruby_sandbox, and we can check that
| | 02:42 | with expand_path.
| | 02:43 | We saw that earlier, sure
enough that's where we are.
| | 02:46 | We are in the ruby_sandbox.
| | 02:48 | Now, this is what you want to use inside your
Ruby files, inside your code, your RB files.
| | 02:53 | You want to use File.dirname file,
because that gives you your starting point
| | 02:56 | relative to that file.
| | 02:58 | We also have the directory class, Dir, and
it has some methods, one of which is pwd.
| | 03:03 | That stands for path to working directory.
| | 03:07 | That tells us where we are right now.
| | 03:10 | Now it return to the same thing that this
whole expand path did, when I gave it the dirname.
| | 03:15 | You still in your code want to use, File.
dirname(__File__), because PWD can change.
| | 03:20 | It keeps track of where we
are right at this moment.
| | 03:23 | This is saying relative to this file.
| | 03:25 | That will always be the same.
| | 03:27 | It will never change.
| | 03:28 | PWD can change as we move around,
and we have the ability to move around.
| | 03:32 | We can tell the directory class, you
know what? Move around. Let's go to chdir
| | 03:37 | for change directory and let's go back one.
| | 03:40 | Let's go into my parent directory, with dot dot.
| | 03:43 | Let's now try Dir.pwd. Sure
enough, I am now on my desktop.
| | 03:48 | Dir.chdir will also take a
absolute path as well as a relative path.
| | 03:54 | I am just going to paste something in here,
so you don't have to watch me type it.
| | 03:57 | But we saw how to do that
effectively with file join earlier.
| | 03:59 | So we make sure we get the right
line separators, the empty string at the
| | 04:03 | beginning says start at root and then we
string all of these together to come up
| | 04:07 | with a string, with the right
separators, and we can change directory into there,
| | 04:11 | and they are sure enough
we are back in our ruby_sandbox.
| | 04:14 | So that let's us move around.
| | 04:16 | What about the contents of the directory though.
| | 04:18 | How do we actually work with those contents?
| | 04:20 | Well, we call the entries class
method on the directory class.
| | 04:25 | So entries and then tell it what directory,
right. It doesn't know what directories.
| | 04:29 | It's not an instance.
| | 04:29 | So I am going to say this directory.
| | 04:32 | So there is the list of entries.
| | 04:34 | It's just an array.
| | 04:35 | It's an array of strings.
| | 04:36 | Now we can turn on and pass those
strings to the file class, we could open each
| | 04:40 | one up, do something, or
we could filter through.
| | 04:42 | We can look for only files that begin
with the letter A for example, and then we
| | 04:46 | could do something to
those, delete them perhaps.
| | 04:48 | The important thing is that all it
is, is an array. It can be sorted.
| | 04:51 | It can be collected.
| | 04:52 | It just simply an array.
| | 04:54 | Most often what we want to do with
that though is we want to call each on it,
| | 04:59 | and that will let us go through each entry.
| | 05:01 | We'll just make it code block.
| | 05:03 | Let's start out by saying print entry
plus colon space, so that will print
| | 05:10 | the name of this file.
| | 05:11 | That string will get
printed with the colon after it.
| | 05:14 | Then let's use some of those methods
we worked on earlier. Let's say If File.
| | 05:19 | is a file, entry and File.readable,
check and see if it's readable or not,
| | 05:28 | entry, then that's File.open up the
file and we're going to open the file name,
| | 05:36 | we'll read from it.
| | 05:38 | We'll be in read mode, we'll pass
another code block, which will return the file
| | 05:42 | that we can work with, and then puts
file.gets, so that will just get back
| | 05:47 | the first line of the file,
and it will output it to irb.
| | 05:51 | That's what it's going to do,
and in that code block,
| | 05:53 | let's go ahead and put an else
statement in here, just because if it's not a
| | 05:59 | readable file, I did a print up here,
and I just want to do a line ending.
| | 06:04 | So I'll just do a simple puts.
| | 06:06 | So we'll just put a line
ending and then return from there.
| | 06:09 | So puts and then end, and then finally last
of all, let's do a final end, here we go.
| | 06:15 | So there it went, an output.
| | 06:18 | So the first two, dot and
dot dot, are directories.
| | 06:21 | This is a directory and the
parent directory is a directory.
| | 06:24 | So it didn't try an output anything
there. Instead this puts happened and
| | 06:27 | it just did a simple return.
| | 06:30 | This though was a file.
| | 06:31 | It's an invisible file,
but it's actually a file.
| | 06:33 | So we did read from it, we pulled its
first line back, then accessing_files,
| | 06:37 | we got its first line, and so on.
| | 06:39 | So every single one of those files
now we pulled back the first line.
| | 06:42 | So it shows how you can loop through
and work with all these directory entries.
| | 06:46 | Now it's also possible to open up a
directory object to instantiate it, or to do
| | 06:51 | open the same way that we did file open
here, but doesn't really not much point
| | 06:56 | to doing it that way, because once you
get inside, really all you can do is work
| | 06:59 | with the entries anyway.
| | 07:00 | So you might as well just go ahead and
use this class method on the directory class,
| | 07:04 | and because so often we want to
loop through all of those, because that
| | 07:08 | such a common procedure,
| | 07:10 | we also have Dir.foreach, and that's
a shortcut to just say take all of the
| | 07:14 | entries and loop through each one.
| | 07:17 | We'll say entry then we'll
just say puts entry. There it is.
| | 07:21 | It just output the list of entries.
| | 07:24 | Making and deleting directories is just as easy.
| | 07:26 | Let's say Dir.mkdir and then
let's say temp_directory, here we are.
| | 07:37 | So it created a directory. Let's take a look.
| | 07:39 | Here it is, temp_directory, and then
we can just go back when we're ready and
| | 07:43 | delete it with delete.
| | 07:49 | Delete temp_directory.
| | 07:50 | Sure enough, there it is. It's gone.
| | 07:52 | Now in order for that to delete to
succeed, not only do we have to have write
| | 07:56 | permissions on the directory that
contains it, just like we did when we were
| | 07:59 | deleting files, also the
directory has to be empty.
| | 08:02 | All right, the directory can't have
anything in i, if we are going to delete it,
| | 08:05 | or it will raise an error.
| | 08:07 | If you want to get rid of something
that has contents, you either need to loop
| | 08:10 | through and get rid of all those
contents first, and then delete the directory,
| | 08:14 | or that file utilities
class that we looked at earlier.
| | 08:17 | The one that we looked at in the
renaming and deleting files movie.
| | 08:21 | You can use file utilities and it has
some removal features that will let you
| | 08:25 | remove the directory, and force it
to remove even if it has contents.
| | 08:30 | So if you really need that
functionality, you can go there.
| | 08:32 | By now you should have a good
understanding of both files and directories and
| | 08:36 | feel very comfortable working
with the file system from Ruby.
| | Collapse this transcript |
|
|
9. Ruby Project: Creating the Food FinderProject overview| 00:01 | Now that you've mastered the essentials
of the Ruby programming language, I want
| | 00:04 | us to apply those
techniques to a real world project.
| | 00:07 | Our goal will be to successfully use the
right Ruby techniques to write some smart code,
| | 00:11 | and not only will you be able to
get experience that will reinforce the
| | 00:14 | lessons that we've covered so far,
it will also give me an opportunity to make
| | 00:17 | some points about the best practices
you should use in your own Ruby projects.
| | 00:21 | Now the project we'll be creating
is something I call the Food Finder.
| | 00:24 | Let's take a moment to get
an overview of the project.
| | 00:26 | Simply put the Food Finder is going to
be a little Ruby program that will allow
| | 00:30 | us to find the food that we're in the mood for.
| | 00:33 | So we'll be able to consult a list of
restaurants and find the restaurant that
| | 00:37 | would be right for us, either to go
out to tonight or to order in from,
| | 00:41 | something like that.
| | 00:42 | So if we were to make a list of the
requirements for the project, it would be
| | 00:45 | that it's a Ruby program
launch from the command line.
| | 00:47 | It's going to serve as a Rolodex of our
favorite restaurants and it's going to
| | 00:50 | do that by saving those
restaurants into a text file.
| | 00:54 | The program will allow user interaction.
| | 00:56 | It's not going to just
simply output a list to us.
| | 00:59 | We are going to be able to actually
interact with it, ask it questions, look for
| | 01:03 | one kind of restaurant, then look
for another kind of restaurant perhaps.
| | 01:05 | We'll be able to list out restaurants.
| | 01:07 | It will give us the name,
the cuisine, and the price.
| | 01:10 | You can certainly add more
attributes to it, but we are just going to be
| | 01:13 | sticking with those three to keep it simple.
| | 01:14 | It will also be sortable by
those three attributes as well.
| | 01:17 | And we'll of course need to be able to
add restaurants to the list, and finally
| | 01:21 | be able to find restaurants by keyword.
| | 01:24 | So those are the goals we're going to hope
to accomplish for the next several chapters.
| | 01:28 | Now we won't be creating this
project inside our ruby_sandbox anymore.
| | 01:31 | I am going to create a new folder
for it that we'll be working in.
| | 01:33 | You can put that folder anywhere you like,
just somewhere where you can find it easily.
| | 01:37 | I am going to have mine on my desktop,
and I have just called it food_finder and
| | 01:41 | to start with I've just put a folder
in there and they are called lib.
| | 01:44 | Lib is short for library.
| | 01:45 | It's a common practice inside Ruby
programs to call all of the files that will
| | 01:49 | be in your library, lib.
| | 01:51 | I think the best way for you to have an
understanding of where we're headed with
| | 01:54 | this project is for me to show you
a demonstration of the final result.
| | 01:58 | So from the command line I am just
going to launch the program and you'll see
| | 02:02 | that it comes up with some
introductory text and it tells me here are the
| | 02:05 | actions that you're able to perform.
| | 02:07 | So let's try the first one.
| | 02:08 | Let's try list. It lists out the restaurants.
| | 02:11 | So it has three columns, Name,
Cuisine, and Price, all nicely formatted.
| | 02:15 | It also gives me a note that says I can
sort using list cuisine or list by cuisine.
| | 02:21 | Let's try a list by cuisine and sure enough.
| | 02:25 | It sorted those by making
cuisine go in alphabetical order.
| | 02:28 | Let's try a list by price.
| | 02:30 | Now it sorted the prices, and it
put the prices into ascending order.
| | 02:35 | Let's try the second
action there. We have got find.
| | 02:37 | So let's try find and let's see what we
get back, and it says find a restaurant.
| | 02:40 | Find using a key phrase to
search the restaurant list.
| | 02:43 | So find tamale, find Mexican or
just find mex. Let's try that.
| | 02:47 | Find tamale, I got back Hot Tamale.
| | 02:51 | Let's try find pita.
| | 02:52 | I got back fast food.
| | 02:54 | Let's try find mex. I got back
to the Mexican again, Hot Tamale.
| | 02:59 | Let's try find 20. I got like
all restaurants that are under $20.
| | 03:05 | That's what they gave me.
| | 03:06 | Let's try the add now, so we should
be able to add a new restaurant to
| | 03:09 | our restaurant finder.
| | 03:10 | We've just gone to some fabulous place
that we loved and let's say that this
| | 03:14 | is called the Paradise Cafe and the
Cuisine type we'll just say Snack, and
| | 03:20 | Average price is $5.
| | 03:23 | So there it is, Restaurant Added.
| | 03:24 | Let's see if it's added. List.
| | 03:25 | Sure enough there it is.
| | 03:26 | Paradise Cafe pops up in the middle of the list.
| | 03:28 | It's being alphabetized by name by default.
| | 03:31 | We could also do list by price again,
and we'll see it at the top or we can
| | 03:35 | do our find for paradise and we'll see just
the Paradise Cafe, if we want to find it again.
| | 03:40 | Last of all quit, and quit
says Goodbye and Bon Appetit.
| | 03:44 | So that's a quick tour of what the
finished product is going to look like.
| | 03:48 | Now we're going to see how to actually
go about creating that using the skills
| | 03:51 | that you have already learned in Ruby.
| | Collapse this transcript |
| Application paths| 00:00 | Most times when you are starting a new
Ruby application, one of the first things
| | 00:04 | you want to do is
establish your application paths.
| | 00:07 | Essentially you are telling your
application, figure out where you were located
| | 00:11 | inside the file system at this point
in time, and then we will be able to use
| | 00:15 | that path as a basis for any relative
paths that need to load in other files,
| | 00:19 | either for requiring them or
for reading and writing to them.
| | 00:22 | Inside my food_finder project folder I've
gone ahead and added a couple of things.
| | 00:26 | I have got my lib folder,
| | 00:27 | which is my library for
different classes of objects.
| | 00:30 | and I've got a starting class
here, guide.rb, which is empty.
| | 00:33 | There is absolutely nothing in there.
| | 00:35 | It's just a placeholder file for now.
| | 00:36 | And then I have got in init.rb. init
is short for initialize and init.rb is
| | 00:41 | sort of a Ruby convention that this is
the starting point of our application.
| | 00:45 | This is what we will use to launch it.
| | 00:47 | Now you don't have to follow that
convention if you don't want. You can call
| | 00:50 | this food_finder.rb, or
you can call it launch.rb.
| | 00:53 | But the convention is init.rb and it
makes it easy for other people to know,
| | 00:56 | hey, this is the file that really
kicks things off and get things started.
| | 01:00 | So we are going to use that
convention for our program as well.
| | 01:02 | So we have got some comments at the top
reminding you that this is how you get
| | 01:06 | started, that you launch it from this file,
and then I'll define my application path.
| | 01:10 | And this should look familiar to you.
All I am doing is taking a constant called
| | 01:13 | APP_ROOT, and I'm setting the
current directory of this file, init.rb.
| | 01:18 | That's where my application resides.
| | 01:21 | That's the folder I'm in.
| | 01:22 | That's food_finder,
wherever that happens to be.
| | 01:25 | Now I have the ability
to locate other files.
| | 01:28 | For example, if we want to
require the guide file, we can say
| | 01:30 | require, APP_ROOT/lib/guide.
| | 01:32 | Now that is a full absolute path
now, not a relative path, right?
| | 01:38 | What we were able to do is get an
absolute path here for APP_ROOT, so now,
| | 01:43 | everything we say after that relative to
the APP_ROOT is an absolute path as well.
| | 01:47 | So this will work, we can launch our
init.rb, we will get no response back,
| | 01:52 | because we aren't actually doing
anything besides setting these values and
| | 01:55 | requiring that empty file.
| | 01:57 | But before we go on, I do want to show
you a couple of other techniques here,
| | 02:00 | including one that we
haven't talked about before.
| | 02:03 | So we have seen that
we can require it this way.
| | 02:05 | Let's comment that line out,
and let's do a different require.
| | 02:09 | We saw that we could use file join,
and we saw that that could be a little
| | 02:12 | bit of a better way to do it, because it will
use the separators based on the operating system.
| | 02:17 | And we can use guide.rb or we can just
do the same thing and leave the rb off,
| | 02:22 | and it will still know where we are.
| | 02:23 | So either of those will work for us.
| | 02:25 | I am just going to comment that one out.
| | 02:27 | and I will go ahead and
comment that one out as well.
| | 02:29 | Those would be slightly superior to
the first way that we did it.
| | 02:32 | An even better way uses a
technique that we haven't seen yet.
| | 02:35 | It's a little bit advanced, so I don't
want to go into great depth about it.
| | 02:38 | But we can use the dollar sign colon
variable that's a very strange looking
| | 02:43 | variable name, but it is
a special Ruby variable.
| | 02:45 | It works a lot like this File does,
File with the two underscores on either side.
| | 02:50 | It's a special magic variable inside Ruby.
| | 02:52 | And what it does is it contains an
array of all the folders that Ruby will look
| | 02:59 | in to find the files that we've asked for.
| | 03:01 | Up here we were asking for a full
absolute path, but if we could tell Ruby about
| | 03:07 | different folders by putting them in
this array, we wouldn't have to give it an
| | 03:11 | absolute path anymore.
| | 03:12 | It would check different places for us.
| | 03:15 | So the most common way that
you do this is you use unshift.
| | 03:18 | That is what's going to append whatever
we want at the beginning, and then we
| | 03:23 | would put something like this in there.
| | 03:25 | Let's go ahead and copy this for now.
| | 03:27 | So File.join but we don't
want to tell it a specific file.
| | 03:30 | What we are telling it is lib.
| | 03:32 | That's the folder I want
you to look in for stuff.
| | 03:35 | And now that we've added to that list
of standard Ruby paths, now we are able to
| | 03:38 | say require and just guide, require 'guide'.
| | 03:42 | So let's go ahead just to make
sure that this is all working.
| | 03:45 | Let's go to our command line. I am
already inside my food finder. You want to
| | 03:48 | navigate to that folder or else you
want to provide a longer path to get there.
| | 03:52 | If I just say Ruby and then init.rb,
and of course we didn't get any results back,
| | 03:58 | because all we did was that
initialization, and then the file was empty.
| | 04:02 | Once it actually required the file,
it didn't do anything beyond that.
| | 04:04 | We are going to need to actually define
that guide class, and then instantiate it,
| | 04:09 | and have it do some work for us.
| | 04:10 | Let's see how to do that next.
| | Collapse this transcript |
| Guide class| 00:00 | In this movie we are going to see
how to create the guide class for our
| | 00:03 | Food Finder project.
| | 00:04 | And the guide class really is going to
be the heart of the food finder, because
| | 00:08 | in that init.rb file, we are
going to instantiate the guide class.
| | 00:12 | We are going to create a new guide,
right, a new instance of the guidebook.
| | 00:15 | And then we will tell that guidebook,
hey, guidebook take over, and at that point
| | 00:18 | the guide class will take over,
and it will handle all of the user input,
| | 00:22 | and do all the processing of the
actions that have been asked for, and handle
| | 00:26 | the user output as well.
| | 00:27 | So really the guide class is going to
be the controller class. It is going to
| | 00:30 | control what's going on.
| | 00:32 | To start out with, we will just outline
the features that we think it's going to have,
| | 00:35 | and then over time we
can come back and fill those in.
| | 00:38 | So I have already got a placeholder for
my guide.rb inside the lib folder and
| | 00:42 | I have gone ahead and just given it the class
declaration of guides, just to get us started.
| | 00:46 | So the first thing we are going to
want to do is initialize this object.
| | 00:49 | What do we need to do to initialize it
and get things off to the right start?
| | 00:53 | Well, it occurs to me that the guide
needs to know where the restaurant file is
| | 00:57 | that we are going to
store all these restaurants.
| | 00:59 | We could simply hard code that value in
at some point, say well, you know what.
| | 01:02 | It's always going to be in the
same location relative to APP_ROOT or
| | 01:06 | relative to the guide.
| | 01:08 | Instead of doing that though, I think
because we will make our classes more
| | 01:11 | general and a little bit reusable,
I think it's better if we actually pass in
| | 01:15 | the path to the file as an argument.
That will then allow us to have
| | 01:19 | different files potentially.
| | 01:20 | We could have a guide that's for Dallas
and a guide that's for Seattle, let's say.
| | 01:24 | So, I think that amount of flexibility
could potentially be very useful for us.
| | 01:27 | Now once we actually pass in that path,
there are going to be couple of things
| | 01:30 | we will just comment for now.
| | 01:32 | We want to locate the restaurant
text file that's at that path, or if we
| | 01:35 | can't locate it, we want to create a
new file, and if the create fails then
| | 01:39 | we'll just exit, maybe there was a permissions
problem, maybe we weren't able to create it.
| | 01:43 | So we want to keep that step in mind.
| | 01:45 | So once we have initialized our
guide object, there might be some other
| | 01:48 | configuration and things that we want
to do, but ultimately what we want to do
| | 01:51 | is launch it and say, "all right,
guide, here you go, take over and run."
| | 01:56 | So I've given it the launch method and
I've given it an exclamation point at the end,
| | 02:00 | just to sort of make it clear
that this is a real strong and powerful
| | 02:03 | method that does a lot of stuff. That's
our exclamation point, just sort of says
| | 02:06 | it's sort of turbocharged.
| | 02:07 | Now the launch method will attempt
a couple of steps. It will give an
| | 02:10 | introduction that just says welcome
to the food finder, here's how you get
| | 02:14 | started, something like that.
| | 02:16 | And after that it will go into a action
loop and it's going to ask for the user
| | 02:20 | input, what do you want to do?
| | 02:21 | and you will have the choice to
input list, find, add or quit.
| | 02:25 | And then we'll do that action,
and then as soon as we have done it,
| | 02:28 | then we are ready to
accept the new response, right?
| | 02:30 | So we listed all the restaurants and then
we say, "right, now what you want to do?"
| | 02:32 | And the user says, "I want to add something."
| | 02:34 | Okay, well, once we added them we say
okay, and now what do you want to do?
| | 02:37 | We want to list it again.
| | 02:38 | So it will just be an action loop that
will keep going until the user quits and
| | 02:42 | then when the user finally quits, then
we will have some kind of a conclusion
| | 02:45 | where we will actually just say goodbye.
| | 02:47 | Now the introduction and
the conclusion are just text.
| | 02:50 | So let's go ahead and
just paste those in for now.
| | 02:52 | You can put in whatever you like. I've
just got something that says 'Welcome to
| | 02:55 | the Food Finder, this is an interactive
guide to help you find the food you crave'
| | 02:58 | and then when they finally leave,
it just says 'Goodbye and Bon Appetit!'
| | 03:01 | So we can now uncomment introduction
and conclusion, and those are actually our
| | 03:04 | method names, right?
| | 03:05 | So it's going to perform this method and
then call this method, right, on this class.
| | 03:11 | So let's go ahead and try all of this.
| | 03:12 | Obviously we are still missing a lot of
this functionality for finding the file,
| | 03:15 | and for the action loop.
| | 03:17 | So the next step of course after we
define the class is to go into init.rb,
| | 03:20 | and get things started.
| | 03:22 | So let's go ahead and say guide = Guide.new,
and we will tell it where the files
| | 03:28 | is going to be, even though we don't
have that functionality built in there,
| | 03:30 | let's go ahead and put this in.
| | 03:32 | So the file is going to be called
restaurants.txt, create a new guide, and
| | 03:36 | once you do, guide.launch!, take it away.
| | 03:39 | Now at this point our init.rb file is done.
| | 03:43 | That's just going to bring up a new
guide instance and get it started and
| | 03:46 | the guide is going to do the rest.
| | 03:48 | So we can save that and let's go to our
command line and just try it and I am
| | 03:51 | already inside my food_finder folder,
you want to navigate there, ruby init.rb.
| | 03:57 | So there we go, we get the
introduction, and then we get the conclusion.
| | 04:00 | We don't get anything between.
| | 04:01 | It didn't do any kind of file
checking for us, or anything like that.
| | 04:04 | We will still have to write that but now we
know that our Ruby program is at least started.
| | 04:09 | All right, we have a class defined.
| | 04:10 | It doesn't do much, but it does
bring it up and launch it for us.
| | Collapse this transcript |
| Restaurant class| 00:00 | So far we sketched out our guide class,
and we have been able to instantiate it
| | 00:04 | and launch it, but it doesn't actually do much.
| | 00:06 | So we need to start going back into
those methods and fleshing them out.
| | 00:09 | And I want to start with the initialize method.
| | 00:11 | if you all remember, the initialize
method in the guide takes a path that we
| | 00:14 | sent them into it, and tries to
find a file located at that path.
| | 00:18 | If it can't find it, it tries to create it.
| | 00:20 | Now we could just put that
functionality right there in the initialize method.
| | 00:24 | But that's not the best option.
| | 00:25 | It's not as object-oriented as it could be.
| | 00:28 | Instead, it's going to be much better
to have a restaurant class and put all of
| | 00:32 | the functionality of dealing with
that data file in the restaurant class.
| | 00:35 | So I have gone ahead and
started the restaurant class.
| | 00:38 | Let's open that up.
| | 00:39 | It's in restaurant.rb in the lib folder,
and it is just a real simple class definition.
| | 00:44 | Notice I have got a class variable
here for file path, so we don't need an
| | 00:48 | instance to have the file path,
and I'll start it out equal to nil.
| | 00:51 | Then I have got three class methods
and we know their class methods, because
| | 00:54 | they have self at the beginning of them.
| | 00:56 | The first is file_exists.
| | 00:58 | So the restaurant class should know
whether it's file exists or not. If not,
| | 01:02 | they will know how to create the file.
| | 01:04 | And then the last class method will be,
that it will be able to look in the file
| | 01:07 | and read the file, and after it's done
reading, it will return instances of the
| | 01:12 | restaurant, making each name,
cuisine and price into an actual instance.
| | 01:17 | So those are the class methods
we are going to be dealing with.
| | 01:19 | Let's just push that aside for a second
and let's open up the guide class, and
| | 01:23 | let's take a look at
this initialize method here.
| | 01:25 | So locate the restaurant text file at the path.
| | 01:27 | Well, we are going to be talking to the
restaurant class now, so we need to say
| | 01:31 | well, restaurant class, restaurant,
set your file path equal to path.
| | 01:36 | Restaurant.file path=path.
| | 01:37 | There's two important things here.
| | 01:39 | The first is whenever we call another
class its a good idea to require that class,
| | 01:45 | because it's now considered a
dependency, we want to make sure that
| | 01:48 | class has been loaded in before this class.
Not just does it exist, but will it be loaded in?
| | 01:55 | And it's be loaded in early enough
that we can start talking about it.
| | 01:58 | Now notice that I'm not
providing a full absolute path here.
| | 02:01 | That's because remember earlier, I told
that init.rb file where it could find
| | 02:06 | everything that it was looking for.
| | 02:07 | I would gave it that lib folder as a path.
| | 02:09 | So the first place it will check for
restaurant.rb is in that lib folder.
| | 02:13 | Okay, so back to our initialize method.
Do you remember what the problem with
| | 02:16 | file path equals is? Hopefully you do.
| | 02:19 | File path, the class variable, is not
accessible from outside of the class.
| | 02:24 | Instead we need to have a setter method,
self.filepath= and then whatever path
| | 02:31 | will make it nil by default, and this
will now be a setter method that will
| | 02:35 | allow us to call it from outside the class.
| | 02:37 | All right, we don't have the ability to
call the attr things for class methods,
| | 02:42 | right, just for instance methods.
| | 02:44 | Instead we have to write it out in full.
| | 02:46 | That's okay, because then we will say
filepath=and we could just say its equal
| | 02:49 | to path, but I am going to actually
say File.join (APP_ROOT) with the path.
| | 02:56 | Now that does assume that the path
will always have to be relative to the app root,
| | 03:02 | but that's fine.
| | 03:03 | That's a restriction I am comfortable making.
| | 03:05 | Otherwise, if we wanted to allow it
to be a file somewhere else, we could
| | 03:08 | require them to send in an absolute path
instead, or we could check and see does
| | 03:12 | the path start with a
slash or something like that.
| | 03:14 | But for now I am just going to
assume that whatever has been passed in is
| | 03:17 | relative to the APP_ROOT.
| | 03:18 | So that will take care for setting file path.
| | 03:20 | So now let's jump back over to initialize,
and let's finish taking care of this.
| | 03:23 | So, we have now set it. We have
would told it where the path ought to be.
| | 03:26 | Now we have the ability to say hey
Restaurant, does that file_exists?
| | 03:32 | And if it does, then let's just say puts
"Found restaurant file" or if not elsif
| | 03:40 | hey Restaurant, try and create_file.
| | 03:42 | So see how I am controlling it form
the guide class, but the actual work is
| | 03:47 | being done by the restaurant class.
| | 03:49 | So if we're able to do that, then
let's copy that line and let's say
| | 03:53 | "Created restaurant file."
| | 03:55 | Or if neither of those happens,
it will just exit, and so we will say puts
| | 04:00 | "Exiting.\n\n" and finally exit!
| | 04:05 | Now we haven't talked about that yet.
| | 04:06 | It's a Ruby method that says okay, no
matter where you are, no matter where
| | 04:10 | you've wandered to inside
different classes, abort the script.
| | 04:14 | Just get out, go back, and just finish up what
you're doing, take me back to the command line.
| | 04:19 | And so that's what it
will do. It will just stop.
| | 04:21 | It doesn't take us back to
init.rb to finish up anything there.
| | 04:24 | It just stops cold, right there in its tracks.
| | 04:27 | So I think that's going to do a
pretty good job on our initialize method.
| | 04:29 | We can go ahead and try running this.
| | 04:30 | It's not going to do much for us,
but let's go ahead and see what happens.
| | 04:33 | Ruby init.rb and it comes
back and says oops! Exiting.
| | 04:37 | And the reason why it exited, was
because, file_exists was not true and
| | 04:41 | create_file was not true.
| | 04:43 | So therefore, it fell to
this condition, Exiting.
| | 04:45 | So we need to write something
for file_exists and create_file.
| | 04:47 | That's what we will do in the next movie.
| | Collapse this transcript |
| Accessing the restaurant file| 00:00 | Now that we have our Guide class
successfully interacting with our Restaurant class,
| | 00:03 | we need to give our Restaurant
class the methods it needs to interact
| | 00:06 | with the file system.
| | 00:07 | We haven't written those methods yet.
| | 00:09 | That's what we will do in this movie.
| | 00:10 | Now just as a quick review. Remember in
the Guide class we are calling a couple
| | 00:13 | different of methods on the Restaurant class.
| | 00:15 | The first is filepath equals, which is
no problem, we have already created that.
| | 00:19 | We also have file_exists
with a question mark after it.
| | 00:22 | We haven't written that method
yet, and Restaurant create file.
| | 00:26 | And notice that I am using them as
part of a conditional statement, if then.
| | 00:29 | So 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:35 | succeeded or failed.
| | 00:36 | So let's jump over to the Restaurant class.
| | 00:39 | Here is our file_exists method, and
let's just make a if statement, if something--
| | 00:44 | we'll come back to it,
return true else return false.
| | 00:48 | So now let's figure what
that condition would be.
| | 00:50 | Well, the first thing is if file path
hasn't been set, well then we can't
| | 00:54 | determine if the file exists.
| | 00:55 | So might as well just
return false at that point.
| | 00:57 | So first we need if filepath.
| | 00:59 | Now we couldn't say if filepath is not
nil, but there is no reason to do that.
| | 01:03 | If this value is nil, then it hasn't been set,
and that will be equal to the Boolean false.
| | 01:08 | But we don't just need to have is set;
we also need to check and make sure
| | 01:11 | that the file_exists.
| | 01:14 | Does the file_exists at filepath?
| | 01:17 | So this will check and see has it been
set and when you go to the file system,
| | 01:21 | is the file actually there.
| | 01:22 | That's a good check for file_exists.
| | 01:24 | Now we could also check for whether the
file is readable, writable, right?
| | 01:28 | Those aren't bad things to test for.
| | 01:30 | If we did, we probably would want to
rename the method something else though,
| | 01:32 | because file_exists,
really is just does it exist?
| | 01:35 | I mean, it doesn't say anything more than
that. Whether the file is actually usable.
| | 01:39 | So let's actually create a new method.
| | 01:41 | We won't end up using this for now,
but just to illustrate the point, file
| | 01:45 | usable, and I want to show you a
different technique for writing these
| | 01:48 | if-then statements, because this
is a very common sort of paradigm in
| | 01:52 | programming, especially in Ruby.
| | 01:54 | So we can say return false unless
filepath, return false unless file.exists.
| | 02:04 | And we can just do a series of these,
all the reasons that it might fail, and
| | 02:08 | let's do return false,
unless file.readable at filepath.
| | 02:15 | And I'll just do one more.
I'll copy it. If the file is writable.
| | 02:19 | So those are all the reasons it might
fail, is the file useable or not, and
| | 02:22 | finally if it passes all of those, return true.
| | 02:26 | So the main reason I wanted to create
this method was to show you that a) it's
| | 02:29 | not a bad idea to check if the file is
readable and writeable, but b) to show
| | 02:33 | you this structure, return false unless,
return false unless. These could be If
| | 02:37 | statements, it doesn't matter.
| | 02:38 | The main point is they are all these
steps along the way where it might fail.
| | 02:42 | But if it passes each and every one
of those, then the last thing is that
| | 02:45 | it will return true.
| | 02:47 | So this is a very common way to write
these kinds of Boolean tests, instead of
| | 02:51 | trying to write If-then statements.
| | 02:53 | Now that we have written this new better method,
file usable, let's actually use that instead.
| | 02:57 | Let's switch back over here from file
_exists to just make it file_usable.
| | 03:01 | We will use that from now on.
| | 03:04 | So I'll leave file_exists in here, just
so we have it for reference, but we are
| | 03:07 | going to be using file_usable.
| | 03:08 | Let's look at create_file.
| | 03:09 | This is something very basic from
where we talked about working with the
| | 03:12 | operating system. file.open and then
filepath, that tells us where it is.
| | 03:17 | We are going to open it in write mode, and
we could provide a code block here, right?
| | 03:21 | That's how we have seen open in
the past, but we don't have to.
| | 03:23 | If we do that, it will just
create the file if it doesn't exist.
| | 03:26 | So we can say create the file, and let's
actually say unless file_exists, then create it.
| | 03:33 | Now if it does exists, it's no big deal
to open it up with write access and then
| | 03:37 | close it again right away.
| | 03:38 | That's what happens here, there's no problem.
| | 03:40 | The one thing we want to be sure
though is that we return whether or not
| | 03:44 | the file is usable.
| | 03:46 | So at the end of all that, is the file usable?
| | 03:49 | That's what we are going to return as a
Boolean, to make sure that the file we
| | 03:52 | just created is going to be usable,
and we'll pass our Boolean test here.
| | 03:56 | So let's try all this now.
| | 03:57 | Let's just go to our command line.
| | 03:59 | I am already inside my food_finder,
so ruby init.rb, and there it is.
| | 04:04 | It says created restaurant file.
| | 04:05 | It said, "there wasn't a restaurant
file, let me create one," and sure enough
| | 04:08 | here is that file, restaurants.txt.
| | 04:10 | You'll find that there's nothing inside of it.
| | 04:12 | It just opened it and closed there right
away, but it did create the file for us.
| | 04:15 | And if we come back and run it a
second time, it says found restaurant file.
| | 04:19 | So that works as well. We were able to
both create it at the first time and
| | 04:22 | then find it on subsequent attempts.
| | Collapse this transcript |
| Handling input in the action loop| 00:00 | So we are off to a good start
with our guide at this point and our
| | 00:02 | initialization routine is basically done.
| | 00:04 | But what we don't have is any kind of
interactivity in our Food Finder and
| | 00:08 | that's what we are going to work on next.
| | 00:09 | So I will just open up the guide.rb
file and the initialize method is what we
| | 00:14 | have been working on so far.
| | 00:15 | We can now call that done.
We have really written it.
| | 00:17 | It is interacting with the Restaurant
class and the Restaurant class is handling
| | 00:20 | everything appropriately.
| | 00:21 | I am going to use a feature of TextMate
to just fold up that initialize method
| | 00:25 | and I can do the same thing for the
introduction and conclusion, because we are
| | 00:27 | basically done with those two.
| | 00:29 | But this launch method here has this
action loop and we need to tackle that now.
| | 00:34 | So what do we want to do?
| | 00:35 | That's what we want to ask the user.
| | 00:37 | We want to ask the user
to give us some feedback.
| | 00:40 | Well, we know how to do that.
| | 00:41 | We have learned how to take user input before.
| | 00:43 | I am going to give the user a prompt
first of all and we will put a space
| | 00:46 | after it and then right after we
print the prompt, then we want to do
| | 00:49 | user_response = gets.chomp.
| | 00:53 | Remember how to do that?
| | 00:55 | So it is going to chop off the line
return or whatever they give us, but it will
| | 00:58 | then wait for them to give us a response.
| | 01:01 | Then we want to do whatever action they give us.
| | 01:04 | So we will say do_action(user_response) and
we will have a method then called do action.
| | 01:11 | Let's put that right here with def do_action.
| | 01:16 | So we will need to pass in
the action as a parameter to that.
| | 01:20 | We will come back to that method in a moment.
| | 01:22 | And then after we do that action we
want to loop. We want to do it again.
| | 01:26 | So let's write a loop, loop do and
then let's indent all of these all the way
| | 01:33 | down here and finally end.
| | 01:37 | So that will just loop through and it
will just keep going, keep going and just
| | 01:40 | looping asking for the user response every time.
| | 01:42 | It doesn't get us out of the loop though.
| | 01:43 | There is no way for us to quit.
| | 01:45 | Now, we could put something right here
that would say break if user_response == quit.
| | 01:54 | That would work.
| | 01:56 | And even better way though I think is
to go ahead and keep all of our actions
| | 01:59 | including quit grouped together, so
that we will do the action quit and we will
| | 02:03 | get back to the result of that action.
| | 02:06 | So if the result that comes back from
passing in that string quit to do action,
| | 02:12 | if that result tells us to quit, then we quit.
| | 02:15 | And so instead of passing the word quit, I am
actually going to just pass the symbol quit.
| | 02:18 | So if the result that comes back is the
symbol quit, then we know we need to quit.
| | 02:23 | So let's jump down here to
do action and write that.
| | 02:26 | The action that we pass in will be different.
| | 02:28 | So we want to have different
response based on what those actions are.
| | 02:31 | But we know that they will be ahead of time.
| | 02:32 | It's either list, find, add, or quit.
| | 02:34 | Those are the four actions
we are going to let them do.
| | 02:36 | So let's have the case statement.
| | 02:39 | So case action and then we can say when
they pass us list, then puts Listing... for now.
| | 02:48 | We will come back and actually
do the action a little bit later.
| | 02:51 | For now we are just going to have
some kind of response. So Finding...
| | 02:58 | and when they have told us to
add, we will do puts Adding...
| | 03:07 | and finally when quit and we
know what quit needs to do.
| | 03:12 | Quit is going to return the symbol quit.
| | 03:15 | Then last of all let's do
else puts and a line return.
| | 03:20 | I don't understand that command.
| | 03:24 | So there we go, so that will--
and then end at the end.
| | 03:28 | So now we have nice case
statement that just handles the action.
| | 03:31 | It says okay, take that action, if
they gave us list, then do the list.
| | 03:35 | If they gave us find, then we
are going to do the finding.
| | 03:37 | If they gave us add, we will do the adding.
| | 03:38 | If they gave us quit, just return the
symbol quit, which gets caught by result
| | 03:43 | and says hey, let's break out of the loop now.
| | 03:46 | So let's go ahead and try this.
| | 03:47 | I will just save it.
| | 03:48 | Let's jump over here to the
Terminal and let's try ruby init.rb.
| | 03:54 | Welcome to the Food Finder.
| | 03:55 | So now it's waiting for me. List, Listing...,
| | 03:58 | find, Finding..., add, Adding....
| | 04:01 | Let's try something garbage.
I don't understand that command.
| | 04:05 | And let's try then finally quit, which
sends the symbol quit and breaks us out
| | 04:09 | of the loop and once it
breaks us out of the loop,
| | 04:12 | that gives us the conclusion
and we then wrap things up.
| | 04:15 | So this works, this is great.
| | 04:18 | I think that loop is not
used that often in Ruby.
| | 04:21 | Usually, there is a better way.
| | 04:22 | If you find yourself just doing a simple
loop, there is probably a better way to
| | 04:26 | write it in most cases.
| | 04:28 | So in this case what we actually
could do instead, what I think is a better
| | 04:31 | way to do it is until result is
equal to quit and then we just have to
| | 04:37 | initialize result up here.
| | 04:38 | So result equals let's
just say nil to start with.
| | 04:42 | So result starts out being nil.
| | 04:43 | Until it is equal to quit, which it's
not the first time, then we do the loop.
| | 04:47 | We don't need this break anymore.
| | 04:49 | Here we can just take that out.
| | 04:52 | So we go through the loop.
| | 04:53 | Is result now equal to quit?
| | 04:55 | If so, then we break out of the loop,
because the until statement told us to.
| | 05:00 | So it is little bit cleaner, a little bit
more succinct and a little bit more Ruby-like.
| | 05:04 | I think that most Ruby programmers
would tend to program it this way instead
| | 05:07 | of using that loop.
| | 05:08 | Loops are just a little bit clunky.
| | 05:11 | The one last footnote that I
want to give you about this
| | 05:13 | now that we have a loop of user input is
that if you need to break out of it, if
| | 05:16 | you wrote something incorrectly and you
are stuck in an infinite loop, from the
| | 05:19 | command line you should be able to use
Ctrl+C. That's hold down the Ctrl key and
| | 05:24 | press C and that should exit out of the program.
| | 05:26 | It should force it to quit.
| | 05:28 | So that's a very useful
keyboard command to know.
| | Collapse this transcript |
| Limiting input| 00:00 | In the last movie we enabled our Guide
class to be able to handle user input.
| | 00:04 | In this movie, I'd like to improve that
a little further by restricting the data
| | 00:07 | that will allow the user to give us.
| | 00:09 | The thing that I am mostly concerned
about is that we are accepting any response
| | 00:12 | from the user here and passing
it right away off to the action.
| | 00:16 | And the action is handling it appropriately.
| | 00:18 | The action, if it doesn't fit one of
these categories, comes up and says,
| | 00:20 | "oh! I don't understand that command."
| | 00:23 | But I think it's better software design if we
actually trap it before we try and do the action.
| | 00:28 | Let's make sure we got valid input
before we run off and try and do it.
| | 00:32 | The other one works.
| | 00:33 | There's no reason that that's wrong.
| | 00:35 | You can do it that way, but I think
it's a slight improvement and it will also
| | 00:38 | give us a place to make some
more improvements a little later on.
| | 00:40 | So, let's go ahead and make that
change. What I want to do is make a new
| | 00:44 | method called get action, and I am
just going to right now move these two
| | 00:49 | lines down into get_action and that
means that these I'll just take away, and
| | 00:56 | instead of being the user_response,
now we will say, well the action is going
| | 00:59 | to be equal to get_action.
| | 01:02 | And then we'll just go ahead and do action.
| | 01:05 | We'll pass in the action here.
| | 01:06 | So, at the end of this, what we want
to do is return the action, which means
| | 01:13 | that of course, my action has
to be equal to my user_response.
| | 01:18 | Now, that probably seems a little bit
redundant, but that's because what I have
| | 01:23 | in mind here is that we can
actually make a quick improvement to the
| | 01:25 | user_response by saying well let's
actually take the response and downcase it,
| | 01:29 | and strip any spaces out of it.
| | 01:31 | So, already we've
improved what the user gave us.
| | 01:33 | We'll make sure that if they gave us all
capital, they have their Caps Lock key on,
| | 01:36 | and they type list,
| | 01:37 | it will still work, because it will
be downcase before we would return it.
| | 01:40 | But the big improvement that I want to make
is that I want this to now be inside a loop.
| | 01:45 | So that it checks to see whether or
not this is a valid action before it
| | 01:51 | actually returns it and says let's get started.
| | 01:53 | So, we need a way that keeps
track of what the valid actions are.
| | 01:56 | So, I am going to come up here at the
top of the Guide, and I'm going to create
| | 01:59 | a class inside the class.
| | 02:01 | Now this is not strictly necessary
to have a full class in here, but I am
| | 02:05 | going to call it Config, and that's
where I am going to put configuration
| | 02:07 | information about the Guide.
| | 02:09 | Having a separate class can be a nice
way to be able to group together some of
| | 02:12 | these attributes and methods, but it
also just illustrates the fact that you can
| | 02:16 | have a class inside of class and
that's mainly what I want to show you.
| | 02:19 | So, it's a little bit overkill in
this case, but it does make the point.
| | 02:22 | So, let's say actions =, and the
actions we are going to allow are list, and
| | 02:27 | find, and add, and quit.
| | 02:31 | Those are the things
that they are allowed to do.
| | 02:33 | Now, we'll need a way to be
able to read that, self.actions.
| | 02:37 | Remember it's not
accessible from outside the class.
| | 02:40 | And I'll use my semicolon, so I'll just put
it all on one line, just return the action.
| | 02:45 | So, notice that I have just got
semicolons here that let me, instead of breaking
| | 02:49 | it up onto several lines, I can just a
one quick line, here is a reader method
| | 02:54 | that will read back those.
| | 02:55 | So, now down here I can actually ask for that.
| | 02:57 | I can say Guide::Config.actions
and that will return that value.
| | 03:05 | So, does it include whatever action
we have been given? Well until it does,
| | 03:12 | we are going to loop.
| | 03:17 | So, see what I have done.
| | 03:18 | It's a loop that's says all right,
let's keep going through, every time
| | 03:21 | we'll loop through and see does the action
that we've been given, is it one of these actions?
| | 03:25 | If so, we can return it. If not then,
we have got to go through the loop again.
| | 03:30 | So, let's start out with action = nil,
so that it has a value the first time
| | 03:35 | through and that first
time it will be equal to nil.
| | 03:37 | So, the nil is obviously not in that
list, so then it will go through again and
| | 03:41 | again and again, until finally, they
give us something that matches and at that
| | 03:45 | point it will already be down
cased and stripped. We'll return it.
| | 03:48 | I'll just put in a comment here to
remind us that that's what it's doing.
| | 03:52 | One nice thing about doing it this
way is that now we have the opportunity
| | 03:54 | to not just say hey! user, we didn't get good feedback.
Instead we can say here are your available actions.
| | 04:01 | If that list changes and we add a
new feature, we add a new action, boom!
| | 04:04 | It gets added to the list automatically.
| | 04:07 | So, we'll take that list of actions,
we'll just join them together with a comma
| | 04:10 | and a space between them and so we
will have a list, saying what they are.
| | 04:13 | Now it's a little weird the first time
you come there to say it, so we might
| | 04:15 | some have something like if action,
which means the first time when it's nil,
| | 04:19 | it won't output this list.
| | 04:21 | It's only if we get a failure.
| | 04:22 | So, let's just try running all this.
| | 04:24 | Let's see how all this goes together.
| | 04:26 | Let's go to the command line
and let's run ruby init.rb.
| | 04:31 | So, here we are, food we crave.
| | 04:33 | So list, Listing. LIST, Listing. Space
space list space space, still works. Listing.
| | 04:40 | If I now type something that's garbage,
it comes back and says oops actions and
| | 04:45 | it gives me a list of the available actions.
| | 04:46 | It's a little bit friendly and
then finally quit when we are done.
| | 04:50 | So again, while it's not strictly necessary.
| | 04:52 | I think that it is better to pull all
this off into its own get_action, because
| | 04:56 | that gives us a place to add some
enhancements in there, and they don't clutter
| | 05:00 | up this launch method, right?
| | 05:01 | get_action contains all the information
it needs to know about how to get the action,
| | 05:05 | and that's where we'll make
sure that the input is valid, before we
| | 05:10 | ask do_action to do what it knows how to do
best, which is to actually perform that action.
| | Collapse this transcript |
| Adding restaurants| 00:00 | Now that we are handling the user
input well, we need to start responding to
| | 00:03 | that input with some meaningful results.
| | 00:05 | The actions inside our food finder.
| | 00:07 | And I am going to start out with the
add restaurant action, because we can't
| | 00:11 | really list or find
restaurants until we have some.
| | 00:14 | So, here we are going to concentrate
on getting the information about the
| | 00:16 | restaurant, and then saving it
to that restaurant's text file.
| | 00:19 | Inside the guide.rb file we have been
working with, we already have a do_action,
| | 00:23 | that takes a string, and if that string
is equal to add, then it's going to do
| | 00:28 | our add action, right.
| | 00:29 | Well, we could put all the code for
that right here inside the case statement,
| | 00:33 | but I think it's better to use this
as sort of a signpost, telling us what
| | 00:36 | method we are to call from here,
and then we'll have one called add.
| | 00:40 | And then I'll make a new method down
here, just call it add, and so when it's
| | 00:45 | equal to add, we'll call the method add.
| | 00:47 | So, all of this will get executed.
| | 00:49 | So, what do we want to do?
| | 00:50 | Well, the first thing I am going to do
is just output something that says all right,
| | 00:53 | we are adding a restaurant.
| | 00:54 | It's sort of like a title. Then we
want to actually create the restaurant,
| | 00:58 | give it its values, its
correct attributes, and save it.
| | 01:02 | Those are the steps we are going to go about.
| | 01:03 | Well, we know how to create a new
restaurant. We create an instance of
| | 01:06 | the object restaurant.
| | 01:07 | restaurant = Restaurant.new.
| | 01:12 | Now in order to add attributes to it,
we need to have instance variables.
| | 01:17 | Those are the attributes.
| | 01:18 | So, if we come back over here to
restaurant, we have written lots of class
| | 01:21 | methods so far, self.filepath, self.file_exists.
| | 01:24 | This is a class variable. We
don't have anything for the instances.
| | 01:28 | So, in order do that let's create attr_
accessor, so it can both read and write
| | 01:34 | for name, cuisine, and price.
| | 01:39 | You can add others if you want.
I am just going to keep it simple by
| | 01:41 | having those three.
| | 01:42 | So, let's jump back over to our guide now,
and we can start to put in values for that.
| | 01:46 | So, we are going to have
restaurant.name = and restaurant.cuisine =
| | 01:55 | and restaurant.price =.
| | 01:58 | So, in order to fill those out,
we need user interaction, right?
| | 02:02 | We know how to do that already. What we
want to do is give the users some kind
| | 02:05 | of a prompt first of all.
| | 02:06 | So, let's say print Restaurant name: ,
| | 02:11 | and then that will then stop and
prompt them using gets.chomp.strip.
| | 02:17 | So, that will take any
spaces out of it at the end.
| | 02:19 | I am going to use that all three times,
but instead of Restaurant name, we are
| | 02:23 | going to then ask for the Cuisine
Type, and let's ask it for the price.
| | 02:32 | We'll call it Average price, so
it's clear that that's what we are
| | 02:34 | really looking for.
| | 02:35 | It's just a rough estimate, Average price.
| | 02:37 | Let me go ahead and make that
lowercase as well so it matches.
| | 02:42 | Okay so now we've got an instance and we've
given that instance attribute its values.
| | 02:47 | Great! What's our next step?
| | 02:48 | We need to save it to that file, so how we
are going to are going to go about doing that?
| | 02:51 | Well, saving it, what it really means
is appending this data to the file, so we
| | 02:57 | can read it back later.
| | 02:58 | So that's what we are going to do.
| | 03:00 | I am going to do it using restaurant.save.
| | 03:03 | We'll have to write that method.
| | 03:04 | That's going to be an instance method
on the restaurant class that we'll save.
| | 03:08 | And if the save succeeds, we'll
return one thing and if it fails we'll
| | 03:11 | return something else.
| | 03:12 | So, if restaurant saves then let's just say
puts and I'll just put a line return here.
| | 03:18 | Restaurant Added line return, line
return and if it fails, I'll just copy that.
| | 03:28 | Let's change it to say
Error: restaurant not added.
| | 03:36 | And let's actually change it to be
Save Error, so it's clear that's what
| | 03:40 | we're talking about. Save Error:
| | 03:42 | Restaurant not added.
| | 03:43 | That will give us some meaningful results.
| | 03:45 | Our results of our save we'll
need to return true or false.
| | 03:48 | So, we'll just want to make sure that the
end we return either true or false for that.
| | 03:50 | So, now let's write that Save method.
| | 03:53 | It's going to be instance method.
I like to put my instance methods below my
| | 03:57 | class methods and I think
most Ruby developers do as well.
| | 04:00 | So, I am going to have all my class
methods at the top, then my instance methods.
| | 04:04 | So, I have got an instance now that needs
to be saved. How does it go about saving?
| | 04:07 | It's going to open up the file and write to it.
| | 04:10 | So, we need to make sure that that
file exists, return false unless file,
| | 04:17 | actually let's say usable, so
we can make sure it's writable.
| | 04:20 | In the past when we were doing create
file for example, we were just using
| | 04:24 | file_exists and file_usable on their own,
just calling those methods, but this was a
| | 04:29 | class method itself.
| | 04:30 | Now we are using an instance method.
| | 04:32 | So, we need to ask the actual class
Restaurant.file_usable, all right?
| | 04:38 | Otherwise it's going to look for an
instance method called file_usable.
| | 04:41 | We need to class method.
| | 04:42 | So, we have to tell it, hey!
you have to ask the class for that.
| | 04:45 | So, now let's go-ahead and open up the file.
| | 04:47 | If the file is usable then we didn't
return false, then we are going to do a
| | 04:50 | File.open, and we know where that's
going to be located, set filepath, and
| | 04:56 | we want to append to the end.
| | 04:58 | So, we are going to be in Append mode
that'll put our file pointer at the end of
| | 05:01 | the file ready to write a new line, and
do File and then what are we are going
| | 05:07 | to actually put in there?
| | 05:08 | Well, we have this file block variable
that we are going to be working with,
| | 05:12 | and we can tell it puts, and then
what do we want to actually put here?
| | 05:16 | There are a lot of
different ways you could do this.
| | 05:18 | I am going to do it by saying okay,
everything I want to input is going to be
| | 05:21 | inside these brackets and then I am
going to do a line return at the end and
| | 05:25 | what I am going to put in here is
going to be an array made up of name,
| | 05:29 | cuisine, and price.
| | 05:32 | And then I will just take that
array and join it together with tabs.
| | 05:37 | So, that's the \t for a tab.
| | 05:40 | And notice I used double quotes
in every case so that these get
| | 05:43 | handled appropriately.
| | 05:44 | Single quotes would not handle
these escaped characters right.
| | 05:47 | So there we go. That will output
a tabbed version of this array.
| | 05:52 | So, it will be name tab, cuisine tab,
price and then a new line return, and that
| | 05:57 | will be essentially how
we'll export a line to the file.
| | 06:00 | So, then we'll say return true at the
end, so that we know that it did succeed.
| | 06:04 | We did get down there.
| | 06:05 | Let's try it out, see if it worked.
| | 06:07 | So, let's go to our command line, ruby init.rb.
| | 06:11 | Welcome to the Ruby Food Finder.
| | 06:12 | What do we want to do?
We want to add. Restaurant name.
| | 06:15 | Let's start with Hot Tamale and it is
going to be Mexican and the price,
| | 06:22 | the average price we'll just say is $25.
| | 06:23 | And it goes back and
says Restaurant Added.
| | 06:26 | Great! Did it actually add it?
| | 06:27 | Let's just hide these results, so
we'll switch here, and let's open up
| | 06:31 | restaurants.txt and sure enough, there
it is. Hot Tamale, there is actually tab
| | 06:35 | here between it, and a tab
here and then a line return.
| | 06:38 | It's ready on line 2 for me to
add another restaurant to it.
| | 06:40 | So it succeeded.
We were able add it.
| | Collapse this transcript |
| Refactoring the add action| 00:00 | In the last movie, we successfully
coded the add action, and it does exactly
| | 00:04 | what we would want it to do.
| | 00:05 | It lets the user input the properties of
the restaurant that they want to create
| | 00:09 | and then it saves them to the restaurant's file.
| | 00:11 | In this movie though, I want us to
look at how we can refactor that action.
| | 00:15 | If you haven't come in contact with
that word refactoring before,
| | 00:18 | code refactoring means rewriting the code
to improve it, to improve its structure,
| | 00:23 | its readability, maintainability,
performance, or its extensibility, being able
| | 00:27 | to extend it, without
modifying behavior or functionality.
| | 00:31 | So that's what we are going to try and do here.
| | 00:32 | The end result is it's still going to
save it to the file, exactly the same.
| | 00:36 | But we are going to see
how we can improve our code.
| | 00:39 | At the moment, our add action is
creating a new restaurant and then setting all
| | 00:43 | of these values one by one and then saving it.
| | 00:46 | That's the behavior I want to change.
| | 00:47 | Instead of creating an object and
adding attributes, I think an improved way
| | 00:51 | to do it is to add that functionality into the
restaurant class, into the initialize method.
| | 00:57 | So initialize, and it's going to take
some arguments. We will make it a empty hash,
| | 01:01 | in case they don't pass any
arguments to us. We will still just go ahead
| | 01:04 | and do the initialization.
| | 01:05 | But if we do get a hash, then let's go
ahead and set name equal to args and then name.
| | 01:13 | Now if we don't get a
name sent, we will get nil.
| | 01:15 | Instead of getting nil, I am going to
have it default to an empty string because
| | 01:19 | I would rather have an empty
string in the name than I would nil.
| | 01:22 | We can do the same thing for cuisine.
| | 01:24 | Cuisine equals args and cuisine
and once again and an empty string.
| | 01:31 | And last of all, price equals args and price.
| | 01:36 | Now this is a very common pattern
that you will see in the creation of
| | 01:39 | attributes in the initialize method.
| | 01:41 | We will book for some value in the
arguments. If it's not there, then we
| | 01:45 | default to a default value.
| | 01:46 | And also, you'll often see these
spaces here done so that everything lines
| | 01:51 | up nice and pretty.
| | 01:52 | It's up to you if you want to do that
or not but that just kind of gives it a
| | 01:56 | nice clean cut look.
| | 01:57 | So you will see that in a
lot of people's code as well.
| | 01:59 | So at the end of this, we will create a
new object and either all these values
| | 02:03 | will be sent to empty strings which
still could be saved to the database if we
| | 02:06 | want to tell it to do that.
| | 02:08 | We could also say well you know what,
don't save it unless you have all three values.
| | 02:12 | We could add something in here that
would actually do some validation.
| | 02:15 | I am not going to do that.
| | 02:16 | I will leave that at something that
you can do, but the save could fail just
| | 02:19 | because the attributes aren't ready.
| | 02:21 | But if we are passed those
attributes, they'll all get set.
| | 02:23 | So now, back on this page, we can set
up something here and say args, this is a
| | 02:28 | different args, of course.
| | 02:30 | This is just going to be a local hash
that we'll be working with and for each
| | 02:33 | of these, we can now say args, and let's put the
brackets around it, and we'll make it a symbol.
| | 02:39 | Right, so in the args name, go
ahead and put whatever they give us.
| | 02:43 | Let's do that for each of these.
I'll just copy this and paste it in for
| | 02:48 | restaurant both times.
| | 02:49 | We will need our closing square
brackets on both of them as well.
| | 02:52 | So now at the end of this, I have a hash
that's ready to pass to Restaurant.new.
| | 02:57 | So Restaurant.new can move now, it
can drop down here, Restaurant.new(args).
| | 03:02 | So we will just pass in whatever args have
got set to the restaurant and then save it.
| | 03:07 | So that's what refactoring is.
| | 03:08 | It's very common thing to be
refactoring in your code to make
| | 03:11 | slight improvements.
| | 03:12 | I think this is slightly better because
now we have an initialize method that's
| | 03:16 | smarter and I think it's a good thing
if our objects can gain some intelligence
| | 03:19 | and be able to have some features and
functionality we might reuse other places.
| | 03:23 | There is more that we can do though.
| | 03:24 | It bothers me a little bit that we
are doing all of this information about
| | 03:28 | filling out a restaurant in the guide class.
| | 03:31 | Seems like the guide class
isn't the right place for it.
| | 03:33 | What I would really like to be able to
do is just tell the restaurant class to
| | 03:36 | handle all this data gathering for me.
| | 03:39 | What I would want to be able to do is
to say instead of restaurant here,
| | 03:43 | let's say restaurant,
and I will just copy this line,
| | 03:46 | Restaurant.build_using_questions, let's call it.
| | 03:50 | So I am just going to tell the
Restaurant, hey, ask the questions you need in
| | 03:53 | order to build yourself.
| | 03:54 | And all of this then can be removed.
| | 03:55 | I am going to cut it, so that I have it still.
| | 03:59 | It's on my clipboard.
| | 04:00 | So right now, all I am doing is saying,
"hey Restaurant, do your thing and when
| | 04:03 | you are done, save."
| | 04:06 | Now let's just jump over here. We are
going to need a new method here that will
| | 04:09 | handle that for us, right.
| | 04:10 | This is going to be a class method
because we are telling the Restaurant class,
| | 04:15 | build_from_questions.
| | 04:21 | And I am going to paste everything
that we had in the other one in there.
| | 04:24 | We are going to need to just do a
quick check to make sure the code is still
| | 04:27 | good for us and it's going to set arguments.
| | 04:30 | It's then going to print the restaurant name.
| | 04:33 | It's going to get a response.
| | 04:34 | Then finally, at the end, it's going to
just do self.new with the (args), and
| | 04:41 | we don't need to set it equal to
restaurant. We can just return that.
| | 04:44 | So return the result of creating a new
object, a new instance, using these arguments.
| | 04:49 | Now all that logic is
contained inside restaurant.
| | 04:52 | If we had now other areas of our guide
class where we wanted to be able to build
| | 04:57 | these questions or maybe we would want
to be able to reuse this class and have
| | 05:00 | other classes be able to call it.
| | 05:02 | It would still have that knowledge
about how to go about building a restaurant
| | 05:06 | instance built into it.
| | 05:08 | So I am going to save both of those.
| | 05:09 | Again, the net functionality
of this is exactly the same.
| | 05:12 | We have cleaned up things a bit, we
have moved things around but we haven't
| | 05:16 | changed the functionality.
| | 05:17 | That's why we consider it refactoring.
| | 05:19 | So let's try it all out from the
command line and make sure everything still
| | 05:22 | works exactly the way we want
and we didn't make any mistakes.
| | 05:25 | ruby init.rb, here we are. Let's add.
| | 05:29 | Oh, we have build_using_
questions is not a method.
| | 05:33 | Why did we not do that?
| | 05:34 | build_from_questions, ah,
using_questions, there we go.
| | 05:38 | So I did make a mistake.
| | 05:39 | So now let's go back and
try it again, ruby init.rb.
| | 05:42 | Now here we are, add.
| | 05:43 | All right, what's the restaurant name?
| | 05:45 | Let's say Cafe Masala, and
that's going to be Indian food.
| | 05:50 | And the average price, we will say it's $30.
| | 05:52 | Okay, restaurant added.
| | 05:54 | Let's just double-check and
make sure that that's true.
| | 05:57 | We'll jump back over here and we'll take a look
at our restaurants.txt file, and there it is.
| | 06:01 | It made a new entry for it.
| | 06:03 | So it did successfully add it. We didn't
change anything. We didn't break any functionality.
| | 06:08 | We just improved our code in the process.
| | 06:10 | And that's what refactoring is all about.
| | Collapse this transcript |
| Listing restaurants| 00:00 | Now that we have a few restaurants saved on
our file, we can now write the list action.
| | 00:04 | We will actually display the restaurants
that are saved, so the user can review them.
| | 00:09 | The process of starting the action
is the same as we did for add. We are
| | 00:12 | going to just have list here called as
a separate method and we are going to
| | 00:15 | define this method here.
| | 00:17 | We also created a stub for saved_
restaurants over here as a class method on
| | 00:21 | restaurant, back at the very beginning.
| | 00:23 | That's what we want to flush out, right?
| | 00:24 | That's going to pull up an array
of all those saved restaurants.
| | 00:28 | Then the list can actually
go about listing them, right?
| | 00:31 | So, let's have the list action. We'll just
copy this first line from adds, all right.
| | 00:36 | So, it's going to be
Listing restaurants, here we go.
| | 00:42 | So, that will be the title here of the page,
and then we know that we want to do restaurants.
| | 00:48 | That's going to be equal to ask
the Restaurant class to return
| | 00:52 | the saved_restaurants.
| | 00:54 | And that will give us an array
that we can go on to display.
| | 00:57 | So, let's go ahead and write that
saved_restaurants method and then we'll
| | 01:00 | worry about the display.
| | 01:01 | So, the saved_restaurants.
| | 01:03 | Read the restaurant file, then
return the instances of the restaurant.
| | 01:07 | That's what we want to do.
| | 01:08 | So, reading the restaurant
file, we know how to do that.
| | 01:11 | That's working with the file system again.
| | 01:12 | Let's just try out with empty restaurants =
and then we are going to read from the file.
| | 01:19 | If file_usable.
| | 01:23 | This is a class method, so I'm able to
use file_usable without putting the class
| | 01:27 | name in front of it.
| | 01:28 | So, if the file is usable, then
let's try and return the restaurants.
| | 01:33 | File is going to be equal to File.new.
| | 01:35 | I am going to do it using the
instantiation of the file technique, instead of
| | 01:39 | the Open command, you can do either
one, filepath, and we are going to be
| | 01:43 | reading from the file.
| | 01:44 | So, we'll just declare it as an r.
Let's go ahead before we forget and do
| | 01:47 | file.close that will remind
us to close it at the end.
| | 01:50 | file.each_line, that's the method we'll use.
| | 01:54 | That will take a block and we'll go
through each one of the lines in the file
| | 01:58 | and it will do something with it.
| | 01:59 | So, I am going to then say, well,
restaurants. The array will be appended with
| | 02:05 | an instance of my new restaurant.
| | 02:07 | So, I want to take that line
and convert it into a restaurant.
| | 02:10 | Now, I could do that do that here,
so that I had the line ready to go as
| | 02:14 | attributes I could pass off to new.
| | 02:16 | I am going to show you a different
technique though, which is Restaurant.new.
| | 02:20 | So I'll create a new instance, no
attributes being sent and as soon as I have
| | 02:24 | the instance, I immediately turn
around and ask that empty instance to import
| | 02:29 | the line, and I'll say line.chomp and
that will make sure that we get the line
| | 02:33 | ending off of there.
| | 02:34 | Now, let's write a method, actually
this is going to be an instance method, so
| | 02:38 | I'll just drop down here below initialize.
| | 02:42 | This is an instance method called import_
line and it will take a line as its argument.
| | 02:49 | Could I've written this as a class method and
done it like I did build using questions? absolutely.
| | 02:54 | I just wanted to show you
a different way to do it.
| | 02:55 | So, you could've condensed this all
down to a class method just like we did here,
| | 02:59 | than then would have passed
something into initialize. Instead though,
| | 03:03 | we are going to create an empty
instance, then populate it.
| | 03:07 | The line itself is tab delimited, right.
So line_array = line.split and we'll
| | 03:14 | split it on those tabs. Now, we'll
have an array and each item in the array
| | 03:18 | will be name, cuisine, and price in that order.
| | 03:21 | So, once we have that, how do we go
about setting all those attributes?
| | 03:24 | Well, we could do @name = line_array 0.
| | 03:30 | That would pull in the first value, or
we could be even fancier and we could
| | 03:33 | say .shift and that would pull
the first item out into name
| | 03:37 | and then we could shift again, because the
next item at that point would be the cuisine.
| | 03:42 | But an even slicker way to do it I
think, since we just have so few of these,
| | 03:46 | is to go ahead and use this triple assignment
in this case. price. When I provide an array,
| | 03:52 | this is an array, even though it
doesn't look like an array, because I don't
| | 03:55 | have the square brackets, it is, and
I say equals to another array, then it
| | 03:59 | attempts to assign the values that are
in the line_array in 0, 1 and 2 to these
| | 04:03 | three values, boom, boom, boom.
| | 04:05 | So, that's a nice way to do it.
| | 04:07 | At the end, once we are done importing
the line, we are going to say return self.
| | 04:12 | Now, think about why we want to do that.
| | 04:14 | Why do we want to return the object itself?
| | 04:17 | Because essentially what we've done is
populated it and the result of this whole
| | 04:21 | operation, creating new returned an object.
| | 04:24 | It returned the Restaurant instance to us.
| | 04:26 | import_line also needs to return
that same instance, because we need that
| | 04:31 | instance to go into that array.
| | 04:33 | Otherwise, if it return let's say true
or false, then what we get pushed into
| | 04:37 | our restaurants, would be
true or false, all right?
| | 04:39 | So, it's important that this
whole operation returns an instance.
| | 04:43 | I want to make sure that you understand that.
| | 04:45 | So, that will take care of it for us.
| | 04:47 | That should take the line, put it into
the attributes of the object and then
| | 04:51 | allow us to put the object into restaurants.
| | 04:54 | The very last thing of course is
that we need to return restaurants.
| | 04:58 | And I'm having the return restaurants
outside of file_usable, so that it'll
| | 05:01 | just return the empty array if the file is
not usable. We'll just get back no restaurants.
| | 05:06 | You could return an
errors or something like that.
| | 05:08 | I am just going to have it say
here were no restaurants to be found.
| | 05:11 | One other consideration that I want to
point to you here is that when we are
| | 05:14 | designing this method, we also have to
ask ourselves if we want to get a fresh
| | 05:17 | copy of these restaurant each time, do
we want to go back to the file system and
| | 05:21 | reload whatever is there?
| | 05:22 | Or do we want to store these results in
a variable, so that they are now booted
| | 05:26 | one time, and we never need to check again?
| | 05:28 | In that case, we could turn this
into let's say @restaurants, right?
| | 05:31 | And we could check to see if
it had been set already or not.
| | 05:33 | I am going to have it so that
it actually reads every time.
| | 05:35 | That way maybe if there's more than
one person working on this file, or if we
| | 05:39 | change the file by actually going into
the file and typing something, we will
| | 05:43 | get a fresh copy each and every time.
| | 05:44 | So, just consider that about
this saved_restaurants method.
| | 05:47 | So, now that we get back an array of
restaurants, let's actually output that array.
| | 05:51 | You should know how to do this.
| | 05:52 | It should be nice and easy.
| | 05:53 | We are just going to say restaurants.each do
and I'll just abbreviate it as rest.
| | 06:00 | So, for each restaurant, puts
rest.name and then lets put a pipe.
| | 06:06 | That's the upper right, + rest.cuisine
and then let's put another pipe, and
| | 06:15 | finally, puts rest.price.
| | 06:18 | Okay now that we have it, let's try it all out.
| | 06:20 | Let's save it and let's go to our command line.
| | 06:22 | I am inside the Food Finder, rubyinit.rb,
and this time we have already added,
| | 06:27 | so we can just say list,
LISTING RESTAURANTS and there we go.
| | 06:30 | We get our list of restaurants back.
| | 06:32 | It went to the file, read them in,
turned them into instances, passed them
| | 06:36 | back as an array to the list action and
the list action then went through that
| | 06:39 | array and output the contents of the array, by
calling these attributes named cuisine and price.
| | 06:47 | In the next movie, we'll take a look at
how we can improve this output, so that
| | 06:49 | it looks a little nicer.
| | Collapse this transcript |
| Improving output| 00:00 | In the last movie, we were able to read
the restaurants back from the text file
| | 00:03 | and output them for our user to see,
but the output is not that pretty.
| | 00:07 | In this movie, I want us to explore
couple of techniques we can use to make that
| | 00:10 | output a lot better.
| | 00:11 | The first thing you'll notice is
that I've added a couple of files in.
| | 00:15 | So these are going to be in the
exercise files or I'm going to show them to you
| | 00:18 | and you can copy them down.
| | 00:19 | But I've created a new folder called
support, and in there is number_helper.rb
| | 00:23 | and string_extend.rb, and we're
going to be using both of those.
| | 00:26 | I've called it support, because these
are just kind of the support files that
| | 00:29 | will help me with my library.
| | 00:31 | It doesn't matter really how you organize them.
| | 00:33 | So let's open up number_helper.
| | 00:35 | This is a module that we can use
as a mix-in into our classes and it
| | 00:40 | borrows heavily on a method that's
inside the Ruby on Rails framework,
| | 00:43 | called number_to_currency.
| | 00:44 | So that's what I've called it again.
| | 00:45 | It's number_to_currency.
| | 00:46 | We provide a number, and then a set of
options, and those options can be the
| | 00:50 | unit, whether it's a $ sign, by default.
| | 00:52 | The precision, how many
decimal places it should have.
| | 00:55 | What it should use between the numbers
as a delimiter, so 1000 would be 1,000,
| | 01:01 | and the separator, the decimal separator.
| | 01:03 | So all of those are configurable.
| | 01:05 | Notice that the format that we're using
to set all of these is the same way that
| | 01:08 | we did it in the Restaurant class.
| | 01:10 | Just to quickly walk you through the
rest of it, we're going to remove the
| | 01:13 | separator if we've been told
not to use any decimal places.
| | 01:16 | Then we're going to take the number, and
we're going to split it on the decimal.
| | 01:19 | We're going to turn into a string,
split it on the decimal so we have two halves.
| | 01:22 | The integer half and the decimal half.
We'll work with them separately.
| | 01:25 | The integer half, we're going to loop
through, and we're going to insert the
| | 01:28 | delimiter after every three places.
| | 01:30 | We're counting backwards is what we're doing.
| | 01:32 | So we're going just move backwards
through it, every three numbers, stop and put
| | 01:36 | in the delimiter that we need.
| | 01:37 | For the precision, now the precision is
equal to 0, well, then there is no decimal.
| | 01:41 | We can just have a empty
string for our precision decimal.
| | 01:43 | Otherwise, let's go through and figure
out what that decimal ought to be, make
| | 01:47 | sure it's not nil, and then,
make sure it's not too large.
| | 01:50 | We're taking the string. This bracketed
call we're doing on the string is saying
| | 01:54 | okay, starting at the first letter,
return everything up to however much
| | 01:58 | precision -1, because the count starts at 0.
| | 02:01 | So that's why we did the -1.
| | 02:02 | So that makes sure it's not
too large. It clips it if it is.
| | 02:06 | If it's too short, then we want to pad it out.
| | 02:08 | So if the number we got like was 10.2,
and we told the precision was 2,
| | 02:12 | we need to add an extra 0.
| | 02:14 | We do that with ljust.
| | 02:16 | That's Left Justify.
| | 02:18 | Let's see how that works.
| | 02:19 | I think that's going to be
useful for us in other places as well.
| | 02:21 | I'll just pop into irb real quick,
and let's just say hello, as a string.
| | 02:25 | If I do ljust, and then tell it a
number, let's say 30, and then I provide a
| | 02:32 | character that I wanted to use to fill in the
remaining characters up to 32. See what it does?
| | 02:38 | Hello, and then however many other
characters it takes till I get to a
| | 02:42 | total length of 30.
| | 02:44 | Let me show you rjust and
I think it will make sense.
| | 02:48 | Now we've right-justified it and we've
filled it in with those extra characters.
| | 02:52 | Now if we don't specify characters,
it gives us spaces, which really makes it
| | 02:56 | look left-justified and right-justified.
| | 02:57 | We also have center, which does the same thing.
| | 03:02 | It just centers it.
| | 03:03 | So it pads it out so it's exactly the
same width, 30 characters every time, but
| | 03:07 | either left-justifying, right-
justifying or centering our string.
| | 03:10 | We'll make more use of that a little bit.
| | 03:12 | But for here, what we're doing is
we're saying okay, pad out until you get to
| | 03:16 | the number of precision, pad it with zeros.
| | 03:19 | So that's what we're using ljust for.
| | 03:20 | So now we've got four strings.
| | 03:22 | We just smash them altogether and
return them, the unit, the integer,
| | 03:25 | the separator, and the
precise decimal. That does it.
| | 03:28 | That will give us something that with
then we can output, number_to_currency.
| | 03:31 | So again it's a module, ready to be mixed in.
| | 03:34 | You can pause the movie if you need
to copy that down, or you'll find it in
| | 03:36 | the exercise files.
| | 03:39 | Now where do we want to add that to?
| | 03:40 | Let's go to the Restaurant class,
and let's require it here, require
| | 03:45 | 'support/number_helper'.
| | 03:49 | That'll make sure that we have the
code loaded and we're ready to use it.
| | 03:52 | So let's include it then
as a mix-in, NumberHelper.
| | 03:54 | That's the second step.
| | 03:57 | Now that functionality is
inside the Restaurant class.
| | 04:01 | So where do we want to use it?
| | 04:02 | I'm going to make a new method
down here called formatted_price, and
| | 04:08 | formatted_price is just going to
return the price, but with formatting.
| | 04:12 | So number_to_currency, and we can
provide different options in the hash as a
| | 04:17 | second argument, or I can just let the
defaults kick in, which is to look like a
| | 04:21 | number with two decimal
places. So I'll save that.
| | 04:24 | Now, this is an attribute we can call.
Just like we can call price, we can call
| | 04:27 | for its formatted price.
| | 04:29 | Let's close that up and open up the guide.
| | 04:32 | Instead of price, now
let's ask for formatted_price.
| | 04:37 | We'll just jump back over to our
Terminal and let's try it all out,
| | 04:40 | ruby init.rb, and list, and there we are.
| | 04:44 | We now get this formatted_price back.
| | 04:46 | So that's an improvement.
| | 04:47 | We saw how rjust and center work.
| | 04:50 | It seems like we can actually make this
look a lot nicer and look a lot more like
| | 04:53 | a table, if we use those.
| | 04:55 | So let's quit out of that and let's
just jump back over here to list and let's
| | 05:00 | try and make that look a little better.
| | 05:01 | For outputting the header, let's center that.
| | 05:04 | Let's actually take that, I'm going to
cut it out, let's center it, but I'm
| | 05:08 | going to do it via a different method,
private method here that I'm going to
| | 05:11 | call output_action_header, and we'll
pass it a bit of text and it will then
| | 05:22 | take that text and output it,
whatever we've asked it to do.
| | 05:25 | So in this case, Listing
restaurants would be the text.
| | 05:31 | So up here I just have to call
output_action_header and then
| | 05:37 | Listing restaurants.
| | 05:38 | Right, so that will now call this
method, pass this argument and do the exact
| | 05:42 | same thing that we were doing before. Okay?
| | 05:44 | I call it output at the beginning. I
like to do if it's just really something
| | 05:47 | that's going to do output for me.
| | 05:48 | That just sort of reminds
me that that's its purpose.
| | 05:52 | So instead of upcasing the whole thing,
I'm going to move that inside in just
| | 05:55 | up-case the text, and then I also
have the ability to apply center to it.
| | 06:01 | Center, and we're going
to give it a width of 60.
| | 06:04 | So I'll save that, after making it uppercase.
| | 06:06 | It's just centered within a 60-character space.
| | 06:08 | Now for the rest of the output here,
let's also put it in that 60-character column.
| | 06:12 | Rather than have you watch me
type the new formatting for that, I'm just
| | 06:16 | going to paste some code in here
and then we'll walk through it.
| | 06:19 | So I'm going to do output_restaurant_table.
| | 06:22 | If we pass it in a set of
restaurants, it auto-output the header.
| | 06:25 | Here we've got the Name, and then it's
going to left-justify that by 30,
| | 06:29 | the Cuisine, left-justify that by 20,
and the Price, left-justify that by 6.
| | 06:33 | Those numbers altogether plus the
spaces are going to add up to 60.
| | 06:38 | Then I'm going to use the multiplier
here to just get 60 dashes to go across in
| | 06:43 | a row, and then I'll go through each
restaurant, and I'll do the same thing.
| | 06:46 | I'll tell it, all right, let's build up a line.
| | 06:48 | We're going to now put a space,
followed by the name, justified, and then the
| | 06:51 | cuisine, justified, and then the
formatted_price, again justified.
| | 06:55 | At the end, once we've built
up that line, we'll output it.
| | 06:58 | So that's what I'm doing there and
I've also added something here that says
| | 07:01 | well, let's also output something
friendly, if there were no listings found.
| | 07:04 | Let's just say that the restaurant was
empty and then we'll have a line at the end.
| | 07:08 | Now instead of doing this loop
through, we've already got the loop built
| | 07:11 | into our output method.
| | 07:13 | So all we have to do is replace all of
that with output our restaurant's table.
| | 07:17 | So it's real clear what we're
doing here. We're outputting the action
| | 07:19 | header, we're getting the restaurants,
we're outputting the restaurants, and
| | 07:23 | I don't need this here.
| | 07:24 | So let's try running this.
| | 07:25 | We'll go back to our Terminal, ruby
init.rb, here we are, list, there we are.
| | 07:30 | Look how much nicer that looks.
| | 07:32 | Now we've got a nice centered title,
we've got columns that make it feel like
| | 07:35 | it's a table, much better output.
| | 07:38 | I'll quit out of it again.
| | 07:39 | The last thing I want to show you is
this string_extend.rb that I've written.
| | 07:43 | This is a very simple class.
| | 07:45 | It opens up the core Ruby string
class and adds another method to it.
| | 07:50 | We saw how we could do that earlier.
| | 07:51 | I wanted to make use of it so you could see it.
| | 07:53 | I created something called titleize.
Ruby has a capitalize method that will just
| | 07:58 | capitalize the first word.
| | 07:59 | It's like capitalizing the
first word of a sentence.
| | 08:01 | But we don't have a way to
capitalize the first letter of every word.
| | 08:05 | So what I've done is said, all right,
take a string, split it up on the spaces.
| | 08:09 | That will turn into an array, go
through each of those and capitalize each word
| | 08:13 | that you come across, and then
rejoin it back together with the spaces.
| | 08:17 | So that will then capitalize every single word.
| | 08:21 | So this will add to the core string
class. We don't include it as a module,
| | 08:25 | right, we're not going to have to mix
it in or anything, but we do have to make
| | 08:29 | sure that it's loaded.
| | 08:30 | So we do up here at the top of the
Guide class, if we're going to make use of it,
| | 08:33 | we want to say
require 'support/string_extend'.
| | 08:40 | That will make sure that it's loaded,
it will get added to the class, and now we
| | 08:43 | can make use of that.
| | 08:44 | So let's do that on our output restaurant table.
| | 08:47 | Let's go ahead and say that the
name will get titleize and the cuisine
| | 08:51 | should also get titleize.
| | 08:52 | So those are now just methods
on a string that we can call.
| | 08:57 | Let's try it one last time, ruby
init.rb, list, and now it's titleized.
| | 09:03 | Let's try add, just so that we can add
restaurant name and let's put this one in
| | 09:07 | lowercase, pita pocket would be the
restaurant, and let's just say it's going to
| | 09:12 | be fast food, and the price will be $10.
| | 09:17 | Restaurant added, now let's list it.
| | 09:19 | Notice that Pita Pocket got
capitalized. Fast Food also.
| | 09:23 | Each of the words got capitalized as well.
| | 09:25 | The one other thing we don't want to
forget to do is now that we have this nice
| | 09:27 | output_action_header method,
we want to make use of it.
| | 09:30 | So if we come up to add, we can
actually use it here on the action header.
| | 09:35 | Right, let's put the parentheses all
the way around it. We don't need to do the
| | 09:39 | upcasing anymore, and we don't need to
do that. We just have to pass it a string
| | 09:43 | and it will take care of the rest.
| | 09:45 | So this output_action_header will give
us a nice consistent way to output the
| | 09:49 | header of every single one of our actions.
| | 09:51 | So, I think that the formatting
improvements we made really helped.
| | 09:54 | It starts to give our program a more
of a professional polished feel to it.
| | 09:57 | And in the process, you were able to
see a variety of techniques that we can use,
| | 10:00 | either by using mix-ins, by
extending Ruby's core classes, or by using some
| | 10:05 | of those built-in formatting
classes, like ljust, rjust, and center.
| | Collapse this transcript |
| Finding restaurants| 00:00 | Now that we are able to add restaurants
to the restaurant file and we are able
| | 00:03 | to list back all the restaurants that
are in the file, the last remaining action
| | 00:07 | that we needed to code is the find action.
| | 00:09 | So we want to be able to find based on
certain keyword and we will only get back
| | 00:14 | to results that match that keyword,
which is instead just having a single
| | 00:18 | command like add or list, we now have
both find and the keyword that we want to find.
| | 00:23 | That keyword is going to be an
argument that's going to be passed into the
| | 00:27 | find method so it can
find what we are looking for.
| | 00:29 | Let's see how to add that functionality.
| | 00:32 | So here I am in guide.rb and in the do
action, I've gone ahead and just added
| | 00:36 | the find, for when find we are going to
execute find and I have written a find
| | 00:40 | method here and we are going to use
the output action header that we just
| | 00:43 | wrote in the last movie.
| | 00:44 | That's all pretty standard stuff.
| | 00:45 | What we need now is a way to pass
in arguments here. Let's say keyword.
| | 00:51 | It's going to be equal to and we
will make it default to nothing.
| | 00:55 | We want to be able to pass that keyword in.
| | 00:57 | To do that it's going to get from the
command line here where we get action.
| | 01:01 | It's going to get passed all the way down
the line until it gets to the find method.
| |
|
|