Skip to content

Instantly share code, notes, and snippets.

@JoseJRVazquez
Last active August 10, 2018 20:12
Show Gist options
  • Save JoseJRVazquez/10934470 to your computer and use it in GitHub Desktop.
Save JoseJRVazquez/10934470 to your computer and use it in GitHub Desktop.
My Lesson in Advanced Classes in Ruby
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