Matthias said:
I am now trying to grasp what a class isand what is is for. I understand
that there a bunch of different classes, but how does that help me?
In your code you use a lot of objects, right? Like 1 is an Integer object,
"hello" is a String object, /\d+/ is a Regexp object, [] is an Array object,
2..3 is a Range object (made out of two Integer objects) and so on.
You will have noticed that those objects all have a different set of methods:
You can do (2..3).each or [1,3,5].each, but you can't do 4.each or /la/.each.
You can do "I'm a string".length, but you can't do 3.length.
You can do 5.times, but you can't do "hello".times.
And it makes sense that it works that way, right? Cause what would the length
of an Integer be? Or what would it mean to execute a block of code "hello"
times?
As you can see, certain methods only make sense when used with a certain kind
of object. But how does Ruby know which objects are supposed to have which
methods? It know because of classes:
Every object is an instance of a class. "hello" is an instance of class
String, 5 is an instance of class Integer (Fixnum actually, but let's not
care about the difference at this point), 3..4 is an instance of class Range
and so on. Those classes describe what properties and methods their instances
have. "hello" has the methods length, gsub, tr and so on because they are
defined as methods of String. 2..5 and ["a","b","c"] have the method each
because in the class Range as well as in the class Array there is a method
called each. And so on.
But what can you do with classes? Well, you can use those classes by using
their instances. But you're already doing that. Even when you do 3 + 5 you're
using two instances of a class (3 and 5 of class Integer) and one method of
that class (the method +).
So what else can you do with classes? For starters you can extend the existing
classes. Let's say you have a method that "censors" a string:
def censor(string)
string.gsub(/./, "x")
end
You can use it like this: censor("hello world"), but now you're thinking that
it would be much more fun if you could use it like this: "hello world".censor
cause after all: all the other methods working with strings are used that way
too. So here's how you'd do that:
class String
def censor()
self.gsub(/./, "x")
end
end
Now you can type "hello".censor and get back "xxxxx" (how very useful, isn't
it). You will have noticed that where we previously said string.gsub we now
said self.gsub. Why's that? That's because the parameter string doesn't exist
anymore. We want to call the method like mystring.censor() without any
paramether. The method should work with the string that's in front of the dot
(also called the receiver of the method) and not with any parameter. So how
do we access the receiver? By using self. Inside a method definition self
will point to the object that the method has been called on. So when you
do "hello".censor, self is "hello" and if you do "bla".censor, self is bla.
Actually we wouldn't have even needed to use self in there: If you call a
method and you don't specify a receiver (i.e. you write foo() instead of
self.foo() ), the receiver is assumed to be self. So gsub(...) would be the
same as self.gsub(...).
So that's how you can extend existing classes. But sometimes that's not
enough. I mean think about what kind of objects does ruby have? Strings,
numbers, ranges of numbers, ranges of strings,... BORING! You're a people
person, you can't be expected to sit in the basement all day and only work
with numbers and strings. So ruby clearly needs a way to use people in your
program. So what we do is we create a class called Person that describes what
properties a person has and what he/she can do (what methods he/she has). So
that we can then use Person objects (I know you usually shouldn't think of a
person as an object, but here it's okay) in our code. Here's how to:
First you decide what properties a person should have. For now let's keep it
small and only let him/her have a name.
class Person
def initialize(firstname, surname)
@fname = firstname
@sname = surname
end
def name()
"#{@fname} #{surname}"
end
def firstname()
@fname
end
def surname()
@sname
end
end
So how do you use this class? Like this:
my_person = Person.new("John", "Smith")
new is a method that can be used on classes. It creates an instance of this
class and then calls a method called initialize on it (that's why we defined
such a method in our class). So now our initialize method gets called with
the parameters firstname and surname. All it does with those two is store
them: the value of firstname gets stored in @fname and the value of surname
in @sname. Variables starting with an @-sign are so called instance
variables. They're properties of an object. If a method sets an instance
variable to some value, all methods that get called on the same object can
now see this value when they access that variable.
Other than initialize there are three other methods: firstname, surname and
name. firstname and surname are boring. All they do is return the value of
the instance variable @fname or @sname respectively. name is a bit different.
It uses @fname and @sname to create the full name and then returns that. Of
course you can do things far more advanced than this with classes, but this
should give you something to start with.
HTH,
Sebastian