Getting at the Instance Variables

หลังจากที่เราได้ Class BankAccount จากบทที่แล้ว เรามาลองเรียก balance ออกมาจาก method Bank account ดู

 my_account = BankAccount.new('Russ')
        puts(my_account.balance)

เราจะเจอ error ว่า

account.rb:8: undefined method 'balance' ... (NoMethodError)

แปลว่าแทนที่มันจะไปหาตัวแปล balance มันกลับไปตามหา method balance แทน … ไม่ต้องทดลอง my_account.@balance นะครับ ตัวแปลใน rails ไม่สามารถเรียกใช้โดยตรงได้จากนอก object

แล้วถ้าต้องการเรียกใช้ตัวแปลจากนอก object สิ่งที่ต้องทำคือกำหนด accessor method ให้กับตัวแปล

 def balance
      @balance
    end

สิ่งสุดท้ายที่ method balance ทำคือค่า @balance ดังนั้นสิ่งที่ return ออกมาคือ @balance หากทดลองเรียบกใช้แบบเดิม

 my_account = BankAccount.new('Russ')
        puts(my_account.balance)

Ruby จะแสดงค่า @balance ออกมาอย่างถูกต้อง … แล้วถ้าต้องการกำหนดค่าให้กับ @balance ล่ะ?

 def set_balance(new_balance)
      @balance = new_balance
    end

set_balance สามารถทำงานได้ดีเยี่ยมเหมือน method balance

my_account.set_balance(100)

ปัญหาคือมันไม่สวยและดูไม่เป็นธรรมชาติ มันจะดีกว่านี้ถ้าเป็น

my_account.balance = 100

ทำอย่างไรเราถึงจะสามารถสร้าง method ให้เป็นธรรมชาติและ ได้คุณสมบัติ encapsulation ไปพร้อมๆ กัน

 def balance=(new_balance)
      @balance = new_balance
    end

เปลี่ยนชื่อ method โดยใส่ “=” ลงไป

my_account.balance=(100)

หรือ

my_account.balance= 100

หรือ

my_account.balance = 100

ถ้าไม่ต้องการจ้างคนมาเขียน set, get จำนวนมาก Ruby มีคำสั่ง attr_accessor ซึ่งจะช่วยสร้าง set และ get ในแบบที่เราพูดถึงข้างต้น

attr_accessor :balance

วิธีนี้ช่วยลด method ได้หลายบรรทัดทีเดียว หรือจะใช้ทีละหลายๆ ตัวแปลก็ได้

attr_accessor :balance, :grace, :agility

และในกรณีที่ต้องการให้อ่านอย่างเดียวให้ใช้ attr_reader

attr_reader :name

ทีนี้ลองเดาว่า attr_writer ใช้ทำอะไร