Object Oriented Programming with Ruby
Classes
"The molds"
Objects
"The things you produce out of the molds"
p and puts
Both _____ and ____ automatically calls to_s
able
Modules often use this suffix on whatever verb describes the behavior that the module is modeling.
class, CamelCaseName, end
Three things needed to begin defining a class
Class States
Track attributes for individual objects. Every object's state is unique, and instance variables are how we keep track.
self.instance_variable
Using a getter method to access an instance variable's value, you just remove the @. But using a setter method to set an instance variable, requires the use of what? (in syntax form)
Ruby Method Look up path
class where instance method is called -> modules starting from the bottom on up -> Super Classes -> Object -> Kernel -> BasicObject
behaviors
what objects are capable of doing
== in Ruby
- for most objects, the == operator compares the values of the objects, and is frequently used. - the == operator is actually a method. Most built-in Ruby classes, like Array, String, Integer, etc override the == method to specify how to compare objects of those classes. - by default, BasicObject#== does not perform an equality check; instead, it returns true if two objects are the same object. This is why other classes often override the behavior of #==. - if you need to compare custom objects, you should override the == method.
equal?()
- the equal? method goes one level deeper than == and determines whether two variables not only have the same value, but also whether they point to the same object. - do not override equal?. - the equal? method is not used very often. - calling object_id on an object will return the object's unique numerical value. Comparing two objects' object_id has the same effect as comparing them with equal?.
=== in Ruby
- used implicitly in case statements. - like ==, the === operator is actually a method. - you rarely need to call this method explicitly, and only need to implement it in your custom classes if you anticipate your objects will be used in case statements, which is probably pretty rare.
CONSTANT look up in Ruby
1st - Ruby looks at the lexical scope of the constant i.e. it checks the class or module that encloses the constant reference to see if it was initialized there. Ruby continues to look through next level enclosed classes or modules until it can't find any. 2nd - If Ruby can't find a CONSTANT definition in the lexical scope, it tries to find it in the inheritance hierarchy by checking ancestors of the class or module that referred to the constant.
Ruby Modules
A collection of behaviors that is usable in other classes via mixins. A module is "mixed in" to a class using the include method invocation.
instance method
A method of a class that changes the state of a class. It must be called from an instance of the class. Instance Methods expose behavior for objects.
What is a module? What is its purpose? How do we use them with our classes?
A module allows us to group reusable code into one place. We use modules in our classes by using the include method invocation, followed by the module name. Modules are also used as a namespace.
multiple
A module can be used in __________ classes.
Why Object Oriented Programming?
A programming paradigm that was created to deal with the growing complexity of large software systems. As applications grew in complexity and size, they became very difficult to maintain. One small change at any point in the program would trigger a ripple effect of errors due to dependencies throughout the entire program. Programmers needed a way to create containers for data that could be changed and manipulated without affecting the entire program. They needed a way to section off areas of code that performed certain procedures so that their programs could become the interaction of many small parts, as opposed to one massive blob of dependency.
Instance Variable
A variable defined in a class for which every object of the class has its own value. Instance Variables keep track of the state of the object. It exists as long as the object instance exists and it is one of the ways we tie data to objects. It does not "die" after the initialize method is run. It "lives on", to be referenced, until the object instance is destroyed. In Ruby an instance variable is denoted with the "@" symbol before the name. (@example)
the super function
Allows us to call methods up the inheritance hierarchy. - super -> calls for the method of the same name up the chain, passing in all arguments if same number and type of arguments are present. - super() -> explicitly calls the method up the chain using no arguments. Useful if your current method takes arguments but the super method up the chain does not. - super(args*) -> passes in the arguments that you want to pass in.
Uninitialized Instance Variable Behavior
Although we have a grade accessor method within our Student class, the @grade instance variable is never initialized within our code and so can't be considered part of state of the Student object represented by ade. Calling ade.grade would return nil because @grade is an uninitialized instance variable and not because we have set its value to nil (the initialize method ignores the grade parameter).
Protected Methods
An in between private and public method approach. - from inside the class, protected methods are accessible just like public methods. - from outside the class, protected methods act just like private methods. We can call a protected method from within the class, even with self prepended. What about outside of the class? The picture demonstrates the second rule, that we can't call protected methods from outside of the class. The two rules for protected methods apply within the context of inheritance as well. There are some exceptions to this rule, but we won't worry about that yet. Protected methods are not used often in practice and that knowledge isn't transferrable to other languages, so if you remember those two rules about protected methods, that should be good enough for the time being.
Collaborator Objects
An object that is assigned to an instance variable in another object.
Benefits of Encapsulation
Another benefit of creating objects is that they allow the programmer to think on a new level of abstraction. Objects are represented as real-world nouns and can be given methods that describe the behavior the programmer is trying to represent. Maintainability, Flexibility, and Extensibility.
Modules and "Mixin"
Another way to apply polymorphic structure to Ruby programs is to use a Module. Modules are similar to classes in that they contain shared behavior. However, you cannot create an object with a module. A module must be mixed in with a class using the include method invocation. This is called a mixin. After mixing in a module, the behaviors declared in that module are available to the class and its objects.
Private Methods
Are only accessible from other methods inside the class.
Instantiation
Creation of an object based on the template provided by the class definition
Don't Repeat Yourself
DRY
getter
Does this code define a setter method or a getter method? def name @name end
setter
Does this code define a setter method or a getter method? def name=(n) @name = n end
Nouns
Extract these into classes
Verbs
Extract these into methods
Encapsulation
Hiding pieces of functionality and making it unavailable to the rest of the code base. (Hiding the implementation details) It is a form of data protection, so that data cannot be manipulated or changed without obvious intention. It is what defines the boundaries in your application and allows your code to achieve new levels of complexity. Ruby, like many other OO languages, accomplishes this task by creating objects, and exposing interfaces (i.e., methods) to interact with those objects.
Class Variable
In Ruby, denoted by a prepended @@ and can be accessed by the class itself is shared among all instances of the class. Class Methods can access class variables regardless of where they are initialized. Objects can access class variables by way of instance methods.
Ruby setter method return value
In Ruby, setter methods always return the argument that was passed in, even when you add an explicit return statement.
Class Instance Variables
Instance variables that are initialized at the class level.
Accidental Method Overriding
It's important to remember that every class you create inherently subclasses from class Object. The Object class is built into Ruby and comes with many critical methods. This means that methods defined in the Object class are available in all classes. Further, recall that through the magic of inheritance, a subclass can override a superclass's method. This means that, if you accidentally override a method that was originally defined in the Object class, it can have far-reaching effects on your code. For example, send is an instance method that all classes inherit from Object. If you defined a new send instance method in your class, all objects of your class will call your custom send method, instead of the one in class Object, which is probably the one they mean to call. Object send serves as a way to call a method by passing it a symbol or a string which represents the method you want to call. Note that you don't need to memorize the Object#send method, or try to keep in mind all other methods that Object implements. Just be aware that you may encounter code like this in the wild and take caution not to accidentally override built-in methods.
Constructor Method
Method for creating a new object which allows you to specify attributes for the object. Triggers whenever a new object is created.
Initializing an Instance Variable
Must define in an instance method and then call the instance method for the instance variable to be initialized.
Fake Operators
Operators in Ruby that are actually methods.
True Operators
Operators in Ruby that cannot be modified or overwritten.
self in OOP
Refers to different things depending on where it is used. - When used on instance methods it helps Ruby disambiguate between local variables being initialized vs the actual method. (Prime example is using self for setter methods) - When self is used within an instance method definition by itself or prependend to a method, it is actually referencing the calling instance(object). So for an obj of Dog class, self.method == obj.method. - When self is prepended to a method definition name, a class method is created. So for the Dog class, self.method == Dog.method. - When self is inside an instance method, it refers to the instance(object) that called the method. - When self is outside the instance methods but inside the class definition, it references the class itself and can be used to define class methods.
attr_accessor :instance_variable
Ruby's built-in way of automatically creating getter & setter methods for us for each instance variable. (in syntax form)
Can you use instance methods inside a class method?
Short answer is no, you cannot use instance methods of a class inside a class method unless you create an instance of the class to call the instance method.
Two things to typically focus on when defining a class.
States and Behaviors
attr_accessor :name, :height, :weight
Syntax to add getter & setter methods to the instance variables of name, height, and weight
Polymorphism
The ability for data to be represented as many different types. "Poly" stands for "many" and "morph" stands for "forms". OOP gives us flexibility in using pre-written code for new purposes.
Classes, Objects, and Instances (House Analogy)
The architectural blue print is the class, the houses produced by those blue prints are the objects, and any given house is an instance.
eql?()
The eql? method determines if two objects contain the same value and if they're of the same class. This method is used most often by Hash to determine equality among its members. It's not used very often. Very rarely used explicitly.
What is meant by the public interface of a class?
The methods exposed by the class to interact with objects of that class.
Instantiation
The process of creating a new object or instance from a class.
Mixin
The term used to describe when a module is mixed in with a class.
can
We (can/cannot) access class variables from within an instance method.
How do we create an object in Ruby?
We create an object by defining a class and instantiating it by using the .new method to create an instance, also known as an object.
mixin a module
What does the following code do? class GoodDog include Speak end
create an object
What does the following code do? class MyClass end my_obj = MyClass.new
define a module
What does the following code do? module Speak def speak(sound) puts "#{sound}" end end
Ovverride the to_s method
What does this code do? def to_s "Text" end
calling a class method
What is this code doing? GoodDog.what_am_i
defining a class method
What is this code doing? def self.what_am_i "I'm a GoodDog class!" end
Class Behaviors
What objects are capable of doing. All objects of the same class have the same behaviors, though they contain different states.
self
When defining a class method, we prepend the method name with the word _______
states and behaviors
When defining a class, we typically focus on what two things?
Inheritance
Where a class inherits the behaviors of another class, referred to as the superclass. This gives programmers the power to define basic classes with large reusability and smaller subclasses for more fine-grained, detailed behaviors.
last
Which module will Ruby try to access first? The first one we mixed in or the last one?
the getter method
Why is it that we can do the bottom code instead of the top code? What are we accessing? def speak "#{@name} says arf!" end def speak "#{name} says arf!" end
Inheritance
a class inherits the behaviors of another class
Initialize
a method that gets triggered whenever we create a new object
Public Methods
a method that is available to anyone who knows either the class name or the object's name. These methods are readily available for the rest of the program to use and comprise the class's interface (that's how other classes and objects will interact with this class and its objects)
instance variables
are scoped at the object (or instance) level, and are how objects keep track of their states
instance methods
expose behavior for objects
super
function that allows us to call methods up the inheritance hierarchy
Encapsulation
hiding pieces of functionality and making it unavailable to the rest of the code base. A form of data protection.
namespacing
organizing similar classes under a module (group related classes)
Uninitialized Instance Variables return value
returns nil
scope
self changes depending on the ________ it's defined in.
class GoodDog < Animal end
set GoodDog as a subclass of Animal
Module
similar to classes as they contain shared behavior. Must be mixed in with a class using the include method invocation.
Polymorphism
the ability for data to be represented as many different types.
Superclass
the class from which subclasses inherit behaviors
Subclass
the class which inherits behaviors from the superclass
attr_reader
the getter method only version of attr_accessor
attr_writer
the setter method only version of attr_accessor
states
track attributes for individual objects