what is OOP?
class and object
blueprint/molds built from it. object can keep the sam behaviors
and different states
from the class
. We can create an object from initialize
method while we call class method new
- encapsulation: hiding pieces of functionality and making it unavailable to the rest of code base.
- polymorphism
class Dog
def initialize(name, age)
@name = name
@age = age
end
end
shelly = Dog.new("shelly", 5)
getter/setter
we can create an object called shelly
and it holds name “shelly” and age with fixnum 5. But what if we want to prints out shelly.name
, it will show undefined method
, then how do we do ? or if we want to change the shelly age to 6, how can we do shelly.age
6=. we can add method:
class Dog < Animal
def initialize(name, age)
@name = name
@age = age
end
def name
@name
end
def age=(input)
@age = input
end
end
with these method, now we can modify the age of shelly and call shelly.name the shelly.name is getter method
, and shelly.age=
is setter method
, but if we have a lots of state we want to get and set, then we have to write lots of code. In Ruby, we don’t want to repeat ourself. So there is setter/getter method built in Ruby. We can use attr_*
class Dog
attr_reader :name
attr_writer :age
attr_accessor :weight
def initialize(name, age, weight)
@name = name
@age = age
@weight = weight
end
end
self
self
in Ruby refer two things, one is class method; the other is the object itself. For example, if we want to set the name to “jonny” inside the method change_name
, we can use self.name
“jonny”=, we also can define a class method. We can call this method without initialize a new object. self
in the class level refer to class itself. In method level, it refer the object who call the method.
class method/instance method
class method can use directly, and if we want to use instance method, we have to initialize an object first then we call the instance method on the object itself. instance method is like the behavior the object holds. the class method are directly caled from the class itself.
class variable/instance variable
class variable has @@
in front of a variable, and @
in front of a variable is instance variable. When an object is created, you can access instance variable all the time with this object. And all the object created from the same clas can access the class variable.
inheritance
unlike other languae, ruby is single inheritance
, one class can inherit from superclass
, the other is called subclass
. But one class only inheritate from one class. we can use the inheritance to avoid duplicate code. The subclass can inherit behavior
from superclass.
method lookup path
we can use method lookup path to see how a method are called. Is this method from the current class? if not, Ruby will trace back to superclass to see where is the method there. If we want to check a speak
method is existed in Dog, we can use Dog.ancestors
to find the method lookup chain. If there is no speak
method in Dog
class then it will look up in Animal
, and then back to BasicObject
class. If there are two class shared some code, we can use method look up chain to find there same ancestors and put this method at the superclass as their both ancestors.
super
super
is when we inherit from superclass
, and we want to modify some code, we can use super
def speak(manner)
super + manner
end
module, mixin
namespace
we can use Module to put the similiar class into a class, if our code get larger and larger, we can avoid to pollute or get confuse with our code. For example, if we define a class called Array
and put it into Rock
module, if we want to use this class, we can called “Rock::Array” to avoid replace the origin built-in Array class. In this way, we can think modules
as container
polymorphism
Because Ruby is single inheritance, how about we want to re use some code again and again? think if we have a Fish
class, and and Dog
class from Mammals
class. But Fish
is not a Mammal
, if we have a method named swim
and both Dog and Fish have the function to swim. How can we do? we can create a module can Swimmable
the in Dog
and Fish
class we can use include
Swimmable
. Althogut Ruby had single inheritance, we can use this mixin way to let Ruby also have the polymorphism. But you can instantiate modules.
private/protected/public
you can not access method from outside the class in the program when the code belongs private
defination. the private method only can be use by other method inside the class. How about self.something
while something
is private method? It doesn’t work. Because, self
here is referred to the object itself, which are not allowed to use private
. If we want to use self.something
by other method inside class and not allowed by the rest of program. We can use protected
reserve word to do that.
fake operators
In ruby, there are lots of operators not true operators
. They are Ruby’s syntactical sugar. Actually, they are methods look like operators. Here are some are true operators:
operators | description |
---|---|
&& |
logical “and” |
.. , ... |
inclusive, exclusive |
?: |
ternary if-then-else |
= series |
assignment |
so all the +, -, *, >>, <<, <=>, !, []=
etc. are methods that look like operators.
class Team
# ... rest of code omitted for brevity
def [](idx)
members[idx]
end
def []=(idx, obj)
members[idx] = obj
end
end
truthiness
block
closure
a closure is a chunk of code that let you save later to execute this code. closure
in Ruby is implement in Proc
object. It is called “closure” because it is said to bind its surrounding artifacts(variable, methods, obejcts etc.) and build an “enclosure”
how block works
do...end
or{...}
- block can passed into an existed method as parameter.
- in Ruby, every method can take a blcok as implicit parameter
- we can use
yield
keyword in the method to invoke passed-in block. - we can use
Kernel#block_given?
method to callyield
it there is a block given.
when to use block in your own method?
- Defer some implementation code to method invocation decision
=method implementator= can defer decision to let method caller
decide what kind of code(block), they want to use here.
- example, the build-in
each
,select
- more flexible
- you want to execute your block to compare before, after action
explicit block
&block
. we can pass it to another method to use this block as parameter
def test(&block)
puts "What's &block? #{block}"
end
test { sleep(1) }
# What's &block? #<Proc:0x007f98e32b83c8@(irb):59>
# => nil
we can use a variable to represent the block withoud yield
it.