Last active
August 10, 2018 20:12
-
-
Save JoseJRVazquez/10934470 to your computer and use it in GitHub Desktop.
My Lesson in Advanced Classes in Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Ok, so Inheritance | |
its not just for young white dudes waiting for their grandparents to fucking keel over at 82. | |
In ruby, Inheritance allows one class to inherit from another class attributes and behaviors (methods) that it didnt have before. The inheriter, much like a young white male, is the child class. The class that it inherits from, rather than being his old money grandparents, is the Parent Class. The lesson says Inheritance is designated with a < symbol, for example: | |
class Daughter < Father | |
end | |
wow, quick right. So for that, the daughter is getting methods from the father. Simple right. But lets go deeper and se how fucked up this can really get for those of us in the cheap seats. | |
class Father | |
def say_hello | |
"hello" | |
end | |
end | |
class Daughter < Father | |
end | |
d = Daughter.new | |
d.say_hello | |
#=> "hello" | |
So the little pain in the ass, the daughter, now gets to use her dads shit. Its like the dad goes on vacation and leaves the keys to his kid, and she can now go hog fucking wild. Or letting her take the Amex to the mall before prom. Damage is done | |
In the forumla above, the daughter inherited from the father, and now the instance is called daughter. His shit, is now her shit. | |
SO, the lesson says parent classes should be as generic as possible. They should be able to describe a broad swath of things, such as the word Dog. The lesson says the following: | |
"The purpose of this class will be to define the general attributes and behavior that all dogs share, regardless of breed. Attributes like having a name, four legs, two eyes and a tail are shared amongst all dog breeds. Behavior like eating, sleeping and barking are also shared amongst all dog breeds." | |
check out the code | |
class Dog | |
def initialize(name) | |
@name = name | |
end | |
end | |
now lets make a method in it | |
class Dog | |
def initialize(name) | |
@name = name | |
end | |
def speak | |
"Ruff, my name is #{ @name }." | |
end | |
end | |
So, now, we are supposed to imagine that many different child classes will be built from this. So for example,we created the Dog class with the idea that we will create child classes for different breeds of dogs. In this respect, the name attribute declared in the Dog class will make sense when applied to any child class. Simply put, our program is assuming that all dogs, regardless of breed, should have names. | |
class Mutt < Dog | |
end | |
Because Mutt inherits from the Dog class, i dont have to specify the initialize method, unless I want to set more attributes that are not generic enough to initialize in Dog. We can access the name attribute from the parent class by using the SUPER method: | |
class Mutt < Dog | |
def initialize(name) | |
super | |
end | |
end | |
The Super method, lets us use a method of the same name in the parent class. Again, this is DRY rearing its head as an overall principle again. I can see the value. Check this shit out | |
2.0.0-p451 :022 > class Mutt < Dog | |
2.0.0-p451 :023?> def initialize(name) | |
2.0.0-p451 :024?> super | |
2.0.0-p451 :025?> end | |
2.0.0-p451 :026?> end | |
=> nil | |
2.0.0-p451 :027 > charlotte = Mutt.new("Charlotte") | |
=> #<Mutt:0x0000010192dc70 @name="Charlotte"> | |
2.0.0-p451 :028 > charlotte.speak | |
=> "Ruff, my name is Charlotte." | |
2.0.0-p451 :029 > | |
So not charlotee can use the dogs method to her own benefit. Saving some typing steps. | |
Extensive inheritance: So, you can have child, and even grandchild classes. An example they give is the ANIMAL Class in the following example: | |
class Animal | |
attr_accessor :name | |
def initialize(name) | |
@name = name | |
end | |
def eat(other) | |
puts "#{@name} ate #{other.name}! #{self.noise}" | |
end | |
end | |
Here comes a child class, Humans | |
class Human < Animal | |
attr_accessor :catchphrase | |
def initialize(name, catchphrase) | |
super(name) | |
@catchphrase = catchphrase | |
end | |
def noise | |
@catchphrase | |
end | |
end | |
here comes the test | |
2.0.0-p451 :052 > a = Human.new("Adam", "Right on!") | |
=> #<Human:0x000001010913f0 @name="Adam", @catchphrase="Right on!"> | |
2.0.0-p451 :053 > b = Animal.new("Chicken") | |
=> #<Animal:0x0000010107bd98 @name="Chicken"> | |
2.0.0-p451 :054 > a.eat(b) | |
Adam ate Chicken! Right on! | |
=> nil | |
2.0.0-p451 :055 > | |
Now taking it a step further | |
2.0.0-p451 :055 > class Englishman < Human | |
2.0.0-p451 :056?> def initialize(name = "Mick Jagger") | |
2.0.0-p451 :057?> super(name, "I can't get no....") | |
2.0.0-p451 :058?> end | |
2.0.0-p451 :059?> end | |
=> nil | |
2.0.0-p451 :060 > a = Human.new("Adam", "Right on!") | |
=> #<Human:0x000001019545c8 @name="Adam", @catchphrase="Right on!"> | |
2.0.0-p451 :061 > mick = Englishman.new | |
=> #<Englishman:0x0000010193d8f0 @name="Mick Jagger", @catchphrase="I can't get no...."> | |
2.0.0-p451 :062 > mick.eat(a) | |
Mick Jagger ate Adam! I can't get no.... | |
=> nil | |
2.0.0-p451 :063 > | |
So taking this a step further with siblings | |
class Dog < Animal | |
attr_accessor :excitment_level | |
def initialize(name, excitment_level) | |
super(name) | |
@excitment_level = excitment_level | |
end | |
def noise | |
"woof" * @excitment_level | |
end | |
end | |
Testing the new Dog class: | |
d = Dog.new("Eight", 3) | |
d.eat(d) | |
#=> "Eight ate Eight! woofwoofwoof | |
All of this leads us to Modules | |
Modules let us group together certain methods. Useful when a group of methods generaically apply to class that are usually unrelated. The lesson uses the following example | |
module Location | |
attr_accessor :x, :y | |
def set_location(x,y) | |
@x, @y = x, y | |
end | |
def distance_to(other) | |
dx = self.x - other.x | |
dy = self.y - other.y | |
Math.sqrt(dx ** 2 + dy ** 2) | |
end | |
def wurr_u_at | |
puts "#{self.name} is at (#{x},#{y})" | |
end | |
end | |
This lets us drop inthe Include statement again, as follows: | |
class Person | |
attr_accessor :name | |
include Location | |
end | |
class City | |
include Location | |
end | |
So now we can all share this wonderful location formula. Share and share alike. Thats the shit. So in the PErson and City modules, both use location. Its called a MIXIN. Im going to try this, and here is what came out | |
2.0.0-p451 :001 > module Location | |
2.0.0-p451 :002?> attr_accessor :x, :y | |
2.0.0-p451 :003?> | |
2.0.0-p451 :004 > def set_location(x,y) | |
2.0.0-p451 :005?> @x, @y = x, y | |
2.0.0-p451 :006?> end | |
2.0.0-p451 :007?> | |
2.0.0-p451 :008 > def distance_to(other) | |
2.0.0-p451 :009?> dx = self.x - other.x | |
2.0.0-p451 :010?> dy = self.y - other.y | |
2.0.0-p451 :011?> Math.sqrt(dx ** 2 + dy ** 2) | |
2.0.0-p451 :012?> end | |
2.0.0-p451 :013?> | |
2.0.0-p451 :014 > def wurr_u_at | |
2.0.0-p451 :015?> puts "#{self.name} is at (#{x},#{y})" | |
2.0.0-p451 :016?> end | |
2.0.0-p451 :017?> end | |
=> nil | |
2.0.0-p451 :018 > class Person | |
2.0.0-p451 :019?> attr_accessor :name | |
2.0.0-p451 :020?> | |
2.0.0-p451 :021 > include Location | |
2.0.0-p451 :022?> end | |
=> Person | |
2.0.0-p451 :023 > | |
2.0.0-p451 :024 > class City | |
2.0.0-p451 :025?> include Location | |
2.0.0-p451 :026?> end | |
=> City | |
2.0.0-p451 :027 > a = Person.new | |
=> #<Person:0x00000103089478> | |
2.0.0-p451 :028 > a.name = "Georgia" | |
=> "Georgia" | |
2.0.0-p451 :029 > a.set_location(2,3) | |
=> [2, 3] | |
2.0.0-p451 :030 > b = City.new | |
=> #<City:0x00000101108130> | |
2.0.0-p451 :031 > b.x = 5 | |
=> 5 | |
2.0.0-p451 :032 > b.y = 7 | |
=> 7 | |
2.0.0-p451 :033 > a.distance_to(b) | |
=> 5.0 | |
2.0.0-p451 :034 > a.wurr_u_at | |
Georgia is at (2,3) | |
=> nil | |
2.0.0-p451 :035 > b.wurr_u_at | |
NoMethodError: undefined method `name' for #<City:0x00000101108130 @x=5, @y=7> | |
from (irb):15:in `wurr_u_at' | |
from (irb):35 | |
from /usr/local/rvm/rubies/ruby-2.0.0-p451/bin/irb:12:in `<main>' | |
2.0.0-p451 :036 > | |
A module can also be used to namespace groups of methods. Namespacing allows you to use the same name for multiple methods and classes, if the need should arise. This is similar to storing similarly named files in different directories. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment