13 Sep 2014
Method Definition
def method(name)
@name = name
end
Method Invocation using self.
If you call a method that does not have a caller, ruby will append self. the caller
When calling the self. inside an instance method => the instance variable itself is returned.
=> self is an object from within the instance method, self changeses depending on what instance method is calling it.
Self being called outside of an instance method refers to the class.
- Use .inspect to see what self is.
- Singleton (ghost) class shadows a particular object, only
=> will not show up in ancestors
+> you can declare methods on objects and is only callable/accessible by that object.
- All classes are objects also.
- DSL - Doman Specific Language => example Rails is a DSL for Ruby, which gives you colligiual sytanx to work with.
- Abtractions - all abstractions leak, not every code base is going fit 100% to a Specific way of writing.
All Classes are Objects also.
=> All classes are objects of the Class class
=> Everything that starts with a capital letter is a constant, including classes => that's why we can store methods in them.
12 Sep 2014
Inheritance
Subclasses inherit attributes and behaviors of superclasses.
When in cases of subclasses and superclass with the same class methods, the subclass will overide the superclass because ruby checks an object class before moving to the superclass.
n the GoodDog class, we're overriding the speak method in the Animal class because Ruby checks the object's class first for the method before it looks in the superclass. So, that means when we wrote the code sparky.speak, it first looked at sparky's class, which is GoodDog. It found the speak method there and used it.
DRY
Inheritance can be a great way to remove duplication in your code base. There is an acronym that you'll see often in the Ruby community, "DRY". This stands for "Don't Repeat Yourself". It means that if you find yourself writing the same logic over and over again in your programs, there are ways to extract that logic to one place for reuse.
Mixing in Modules
Another way to DRY up your code in Ruby is to use modules. We've already seen a little bit of how to use modules, but we'll give a few more examples here.
Extracting common methods to a superclass, like we did in the previous lesson, is a great way to model concepts that are naturally hierarchical.
Inheritance vs Modules
Now that you know the two primary ways that Ruby implements inheritance, class inheritance and mixing in modules, you may wonder when to use one vs the other. Here are a couple of things to remember when evaluating those two choices.
You can only subclass from one class. But you can mix in as many modules as you'd like.
If it's an "is-a" relationship, choose class inheritance. If it's a "has-a relationship, choose modules. Example: a dog "is an" animal; a dog "has an ability to swim.
You cannot instantiate modules (i.e., no object can be created from a module) Modules are used only for namespacing and grouping common methods together.
Method Lookup Path
Now that you have a grasp on both inheritance and mixins. Let's put them both together to see how that affects the method lookup path. Recall the method lookup path is the order in which classes are inspected when you call a method.
There are several interesting things about the above output. First, this tells us that the order in which we include modules is important. Ruby actually looks at the last module we included first. This means that in the rare ocurrance that the modules we mix in contain a method with the same name, the last module included will be consulted first. The second interesting thing is that the module included in the superclass made it on to the method lookup path. That means that all GoodDog objects will have access to not only Animal methods, but also methods defined in the Walkable module, as well as all other modules mixed in to any of its superclasses.
Private, Public, and Protected Methods
Public Methods are available to all
Non-callable inside or outside a class but can be interpolated
Protected methods act as public methods inside the class, therefore can be called but act as private methods outside of the class.
private
def human_years
self.age / DOG_YEARS
end
sparky = GoodDog.new("Sparky", 4)
sparky.human_years
We get the error message:
NoMethodError: private method `human_years' called for
#<GoodDog:0x007f8f431441f8 @name="Sparky", @age=28>
We have made the human_years method private by placing it under the private reserved word. So what is it good for if we can't call it? private methods are only accessible from other methods in the class. For example, given the above code, the following would be allowed:
Assume the method definition below is above the "private" keyword
def public_disclosure
"#{self.name} in human years is #{human_years}"
end
Note that in this case, we can not use self.humanyears, because the humanyears method is private. Remember that self.humanyears is equivalent to sparky.humanyears, which is not allowed for private methods. Therefore, we have to just use human_years. In summary, private methods are not accessible outside of the class definition at all, and are only accessible from inside the class when called without self.
11 Sep 2014
- Come up with requirements/specifications - that will determine your own scope.
- Application logic, sequence of steps.
- Translation of those steps into code.
- Run code to verfiy logic.=end
Sequence of steps
- Draw a board
- Assign Player to "x"
- Assign Computer to "o"
Loop until a winner or all squares are taken
- Player 1 picks an empty square
Check for winner
- Player 2 picks an empty square
- Check for winner
- If there is a winner, show winner; else "It's a tie"
require 'pry'
#create a way to allow players to input choice on tictactoe board, hash
def initialize_board
b = {}
(1..9).each {|position| b[position] = ' '}
b
end
#define board position where player/computer choice will go
def draw_board(b)
system 'clear'
puts " #{b[1]} | #{b[2]} | #{b[3]} "
puts "--------------"
puts " #{b[4]} | #{b[5]} | #{b[6]} "
puts "--------------"
puts " #{b[7]} | #{b[8]} | #{b[9]} "
end
def empty_position(b)
b.select {|k, v| v == ' '}.keys
end
def player_picks_square(b)
puts "Pick a square (1 - 9):"
#make sure your gets.chomp is getting the state that your hash key is
position = gets.chomp.to_i
b[position] = 'x'
#binding.pry
end
def computer_picks_square(b)
position = empty_position(b).sample
b[position] = 'o'
end
def check_winner(b)
winning_lines = [[1,2,3], [4,5,6], [7,8,9], [1,4,7], [2,5,8], [3,6,9], [1,5,9], [3,5,7]]
winning_lines.each do |line|
if b[line[0]] == 'x' and b[line[1]] == 'x' and b[line[2]] == 'x'
return 'Player'
elsif b[line[0]] == 'o' and b[line[1]] == 'o' and b[line[2]] == 'o'
return 'Computer'
else
return nil
end
end
end
#sets local variable b from the initialize method (inner_scope) equal to board, a variable defined in the outter scope
board = initialize_board
draw_board(board)
#loop until
begin
player_picks_square(board)
computer_picks_square(board)
draw_board(board)
winner = check_winner(board)
end until winner || empty_position(board).empty?
if winner
puts "#{winner} won!"
else
puts "It's a tie!"
end
10 Sep 2014
What is OOP?
A way for progammers to deal with large, complex systems.
One small change could be catastrophic in terms of the impact it could have on relevant parts within the system.
Prorgrammers needed to create containers for code that could be changed without impacting the entire program. To section off code that performs certain procedures so that it became an interation of many small parts as opposed to one massive blob of code dependenies.
Encapsulation
is hiding peices of functionality and making it unavailable to the rest of the code base. It is form of data protection so that the data cannot change or be manipulated without intention. This allows your code to achieve new levels of complexity creating objects and exposin interfaces (i.e. methods) that allow these methods to interact.
Polymorphism
ability for data to be represented as many different types.
Allows pre-written code to be used for different purposes.
Inheritance
class inherits the behavior of another class -- referred to as the superclass.
This gives Ruby Programmers the ability to define large usabilty and smaller Subclass, with more defined, detailed behavior.
Modules
Modules are similar to classes in the they contain shared behavior, however you cannot create an object with a module. A module, must be mixed in with a class using the reserved word: include. This is called a "mixin" and after used in a module, the behanviors declared in the module are available to the class and its objects.
What are objects?
In Ruby, everything is an object.
Objects are created from classes.
Class
Ruby defines attributes and behaviors of its objects in classes
Instantation
creating an object/instance of a class
Module
A collection of behaviors that useable by other classes, called mixins using the word "include"
Example:
Create a class, create an object, use a mixin.
module Speak
def speak(sound)
puts #{sound}
end
end
class HumanBeing
include Speak
end
jamela = Humanbeing.new
jamela.speak('Hello!')
07 Sep 2014
Items covered:
- Classes, Instances, & Objects
- Modules
- Inheritance
- Method Lookup Chain
- Procedural vs OOP
Classes & Objects
- Objects are instantized through classes and contant states and behaviors
- Classes are the cookie cutters
- Instance methods encapsulate behaviors and are defined in classes.
- Instance variables = state
- Instance methods = behaviors
Interesting syntax when using equals, setter:
def set_name=(new_name)
@name = name
end
jamela = User.new
jamela.set_name = "Jam"
or
def set_name(new_name)
@name = name
end
jamela.set_name("Jam")
Setters:
You have to use .self when using the setter method within an instance method of the same class.
Instance methods are like raw data and you can access them but in general, you always want to use the getters and setters when available for encapsulation and santization.
Class Variables:
Track states that are common across all instances within a class.
#To keep track of number of objects
@@class = 0
def initialize(n, h, w)
@name = n
@height = h
@weight = w
@@count += 1
end
@@class_variable +=1
Class Methods:
Performs behaviors at the class level
def self.total_count
"The total number of dogs is #{@@count}"
end
puts Dog.total_count
Inheritance
SubClass < SuperClass
object.ancestors shows you the method look-up chain
Namespace
class User < ActiveRecord::Base
refers to the inheritance of the Base class inside the ActiveRecord module
Just like with Cms::User - refers to the User class in the CMS module.
Modules
Allows you to mixin in behavior. The difference between modules and classes are that modules cannot be instantiated.
module Swimmable
def swim
puts "I'm swimming!"
end
end
In method, you can mixin in the module by typing "include Swimmable".
When creating modules you simply add "-able" to the end of your method name and then type "include swimmable" in the method you want to add that behavior.
-In method lookups, a module that is mixin will superecede (be listed first) super classes. This means that if a module and a superclass has the same method, the module method will have precedence. When mixin two modules, the method lookup chain will be effected based on reverse inclusion, meanging the last module included will be looked at first.
The point of modules is extract code that is non-specific to a class... and make it reusable.
Some modules can require methods or behaviors:
module Fetchable
def fetch
#{name} is fetching!
end
end
The above module requires the name getter method look up chain
OOP vs Procedural
Procedural thinks about "what happens next..." and small changes can have big impacts throughout your code.
OOP thinks in terms of objects and how they behave Generally consider classes to be nouns and verbs to be methods. Start by first writing out requirements in pseudo-code.