Ruby on Rails 網站程式設計基礎班

LESSON 4

Quiz 1

Welcome to Ruby on Rails!

Your First Rails App

$rails new my_app_name

Bundle Install

$rails new my_app_name

Self

# 現在我們知道用 attr_accessor,Ruby 會自動把 getter 
# 和 setter method 產生出來
class Person
  
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def greet
    puts "Hello, my name is #{name}"
  end
  # 但假設說我需要在 class 裡面其他的 instance method 裡
  # 呼叫 getter 和 setter method
  def change_info(n, a)
    # 希望能像在使用 setter method 一樣, bob.name = "Boob"
    name = n
    age = a
  end

end

bob = Person.new("bob", 17)
# 用 change info 改變 bob 的 name 和 age
bob.change_info("Bob", 30)

puts bob.name
puts bob.age
# => bob
# => 17
# 但是 bob 的資料卻沒變,為什麼? 
# ruby 以為我們在 change_info 裡的 name 和 age 是指變數而不是 getter methods

More Self

 

# self 可用於:
# 1. 在 class 裡呼叫 setter / getter / instance methods
# 2. 宣告 class method 時
# 但是 self 本身是什麼?

class Person
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def greet
    puts "Hello, my name is #{self.name}"
  end
  # 用這個 method 把 self 印出來
  def who_am_i
    puts self
  end
end

bob = Person.new("bob", 17)
bob.who_am_i
# <Person:0x007ff1ba087dd0>  self 在 instance method 裡
# 是指呼叫 instance method 的 object
# 所以在 instance method 裡面 self.age = bob.age

More Self

 

class Person
  attr_accessor :name, :age

  #今天我要是在class裡,instance methods 外看 self
  puts self

  def initialize(name, age)
    @name = name
    @age = age
  end

  def greet
    puts "Hello, my name is #{self.name}"
  end
end

# => Person
# 所以在 class 裡面,instance method 外面,self 是指 class 自己
# 在在 class 裡面,instance method 裡面,self 是指被創出的某 object 

Class Methods

# class 可以想像成是物件的模板/藍圖,但是他本身也可以被定義一些 method

class Person
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  # 定義 class 自己的 method
  def self.hello
    puts "hello, i am Person Class"
  end
end

# 呼叫方式
Person.hello
#=> hello, i am Person Class

Class Variables

# 如果說 instance variable 是綁定物件的資料,那 class variable
# 就是綁定 class 本身的資料
class Person  
  attr_accessor :name, :age

  # 宣告時前面加兩個 @@
  @@number_of_people = 0

  def initialize(name, age)
    @name = name
    @age = age
    # 每創一個新的 object,就會被加一次
    @@number_of_people += 1
  end

  def self.hello
    puts "hello, i am Person Class"
  end

  # 回傳 @@number_of_people
  def self.info
    @@number_of_people
  end
end

# 呼叫方式
puts Person.info
bob = Person.new("Bob", 17)
puts Person.info
# => 1
sam = Person.new("Sam", 32)
puts Person.info
# => 2

Constants

# constant 就是有些時候會遇上一些在程式裡不應改變的變數
# 像是圓周率、稅率、法定成年的年紀 etc.

class Person  
  # 宣告 constant,全部大寫
  LEGAL_AGE_TO_DRIVE = 16

  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  # 看這個人是否已到可以考駕照的年齡
  def can_drive?
    if self.age >= LEGAL_AGE_TO_DRIVE 
      puts "yes #{self.name} can drive"
    else 
      puts "no #{self.name} can't drive"
    end
  end

end

bob = Person.new("Bob", 17)
bob.can_drive?
#=> yes Bob can drive

Class Inheritance

# 我們希望在建立新的 class 時,新的 class 也包含了舊的 class 的方法和特性
# 這時就可以使用 inheritance(繼承)
# 讓我不用重新寫很多東西
class Person  
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def greet
    puts "hello, my name is #{self.name}"
  end
end

# 使用 < 來代表繼承
class Engineer < Person

end

class Salesman < Person

end

bob = Engineer.new("Bob", 17)
sam = Salesman.new("Sam", 32)

bob.greet
sam.greet

# => hello, my name is Bob
# => hello, my name is Sam
# Engineer 和 Salesman 繼承了 Person 的 greet 方法

Super

class Person  
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def greet
    "hello, my name is #{self.name}"
  end
end
# 如果我希望在改變 Engineer 的 greet
class Engineer < Person
  # override (覆寫) 原本 Person 的 greet
  def greet
    # super 會呼叫 parent class 裡面同樣名字的 method
    # 注意 super 只能在 method 裡面使用
    puts super + ", I know how to write Ruby"
  end
end

bob = Engineer.new("Bob", 17)
bob.greet
#=> hello, my name is Bob, I know how to write Ruby

Module

# 可把 module 想像成工具箱,本身並不是 class
# 不可 new,只能被 include 到其他 class 裡面使用
module Knowledge
  def math
    puts "I know math"
  end
end

class Person  
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def greet
    puts "hello, my name is #{self.name}"
  end
end

class Engineer < Person
  include Knowledge
  def greet
    puts "I am an Engineer, my name is #{self.name}"
  end

end

bob = Engineer.new("Bob", 17)
bob.math
# => I know math

Method Override

class Person  
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def greet
    puts "hello, my name is #{self.name}"
  end
end

# 如果我希望在改變 Engineer 的 greet
class Engineer < Person
  # override (覆寫) 原本 Person 的 greet
  def greet
    puts "I am an Engineer, my name is #{self.name}"
  end
end

# 創立一個叫 German 的子類別
class German < Person
  # override (覆寫) 原本 Person 的 greet
  def greet
    puts "Hallo, mein name ist #{self.name}"
  end
end

bob = Engineer.new("Bob", 17)
martin = German.new("Martin", 20)
bob.greet
martin.greet
#=> I am an Engineer, my name is Bob
#=> Hallo, mein name ist Martin

Method Lookup

class Engineer < Person
  include Knowledge
  def greet
    puts "I am an Engineer, my name is #{self.name}"
  end
end

bob = Engineer.new("Bob", 17)
bob.math
# => I know math

# 尋找 Engineer 的祖先們
puts Engineer.ancestors

# Engineer
# Knowledge
# Person
# Object
# Kernel
# BasicObject

# 一旦 object 呼叫了一個它的 Class 裡面沒有的 method
# 他就會依序找他所有的祖先,若找到了有這個 method 的祖先,就使用這個祖先類別的 method

Public Method

 

# method 有三種不同的存取限制
# public 就是所有的人都可以直接存取

class Person  
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end
  # greet 就是 public method
  def greet
    puts "hello, my name is #{self.name}"
  end
end

#可以在程式的任何地方被使用

Private Method

 

# private 是只有在類別內部才可以存取
# 適用於有些時候,你希望一些 method 不會被程式的其他地方使用到(像是金流、身分證字號 etc.)
class Person  
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def greet
    puts "hello, my name is #{self.name}"
  end

  def identity
    #只能在 class 裡面被其他 instance method 呼叫,前面不能加 self
    puts "secretly, #{secret_method}"
  end

  private # 先寫 private 關鍵字

  def secret_method
  	"I am Iron Man!"
  end
end

bob = Person.new("bob", 17)
bob.identity
# secretly, I am Iron Man!
# private method 不可直接被物件呼叫
bob.secret_method
#=> private method `secret_method' called
#=> for #<Person:0x007ff182033498 @name="bob", @age=17> (NoMethodError)

Protected Method

 

# protected 是介於 public 和 private 之間
# 從 class 外面來看,protected 就像 private,不能被物件使用
# 從內部看,它就像一般的 method,可用 self 呼叫
class Person  
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def greet
    puts "hello, my name is #{self.name}"
  end

  def identity
    #在 class 裡面可被其他 instance method 呼叫,就像一般
    puts "secretly, #{self.protected_method}"
  end

  protected # 先寫 protected 關鍵字

  def protected_method
    "I am Spider Man!"
  end
end

bob = Person.new("bob", 17)
bob.identity
# secretly, I am Spider Man!
bob.protected_method
# => protected_class.rb:31:in `<main>': protected method `protected_method' called for
# => #<Person:0x007fb9f3033428 @name="bob", @age=17> (NoMethodError)

Ruby Style Guide

Homework 2

  1. Refactor Rock Paper Scissors in      Object Oriented Style
  2. 加上能上使用者輸入名字的功能,並會印出加上使用者名字的結果
  3. Push to github

ntu_ror_261_lesson4

By Eugene Chang

ntu_ror_261_lesson4

  • 943