Những điều yêu thích của tôi về ngôn ngữ lập trình ruby
Bài đăng này đã không được cập nhật trong 4 năm
1. Biến trong ruby
- Trong Ruby một Object không thể access trực tiếp tới một biến trong class.
 - Bắt buộc phải viết Setter và Getter cho một biến nếu muốn access biến trong Ruby Class.
 
class Test
 @x
 def get_x
   @x
 end
 def set_x value
   @x = value
 end
end
- Như ví dụ trên ta không thể accsess tới biến @x bằng cách Test.new.x mà chỉ có một cách duy nhất là gọi qua method get_x và gán giá trị bằng method set_x (thử code đi ạ).
 - Method attr_accessor.
 
class Test
  attr_accessor :x
end
- Khi sử dụng attr_accessor ta có thể access biến x bằng cách Test.new.x, lúc này các bạn sẽ nghĩ điều này mâu thuẫn với 2 cái gạch đầu dòng bên trên vì như đã nói Object không thể trực tiếp access biến x như vậy, mà phải thông qua Getter và Setter:
 
Trả lời : Khi sử dụng method attr_accessor :x Ruby đã ngầm định tạo ra hai method Setter và Getter như bên dưới, vì thế khi ta gọi Test.new.x thực chất là ta gọi đến method x() để access biến x, tương tự khi gán giá trị Test.new.x = value ta sẽ gọi đến method x=()
   #Getter
     def x
       return @x
     end
    #Setter
    def x= value
      @x = value
    end
2. Đối tượng
- Khi dùng một Object của một class để truy xuất, Ruby luôn hiểu bạn đang truy xuất vào một method
 - Trong một số ngôn ngữ khác như Java, bạn không thể có hai thành phần trùng tên trong một class (ví dụ khi đã có biến x thì bạn không thể đặt tên một method tên là "x") vì Java sẽ không biết bạn truy xuất thành phần nào khi bạn gọi tới x.
 
     package test
     public class A{
       public string a;
       public void a{}
     }
- Nhưng trong Ruby mặc định là bạn đang gọi tới một Method, vì vậy có thể thoải mái đặt tên biến trùng với tên hàm mà không sợ nhầm lẫn là đang gọi cái gì trong class.
 
	class Test
      @@x
      def self.x
      endope
    end
Khi gọi Test.x thì Ruby sẽ hiểu ta đang access vào một method có tên là "x". Đây cũng là một lý đo để chứng minh thêm cho việc ta bắt buộc phải viết Getter và Setter cho Variable trong Ruby (Vì object chỉ có thể gọi tới method mà không thể gọi trực tiếp tới biến).
3. Scope
- Class Scope: (Tạo ra một vùng nhớ và đặt vào vùng nhớ đó những thành phần mà bản thân con trỏ của chính class đó có thể access)
 - Object Scope: (Tạo ra một vùng nhớ và đặt vào đó những thành phần mà object của class đó có thể access)
 
    class test
    attr_accessor :x
    @@y = 1
    def seft.get_y
      @@y
    end
    def gety
      @@y
    end
- Khi compile một Class như trên Ruby sẽ tạo ra 2 Scope
- Một Class Scope mà chính con trỏ Test trỏ tới.
 - Một Object Scope mà con trỏ Test.new (object của Test) trỏ tới.
 
 - Trong ví dụ trên, những thành phần lằm trong Class scope bao gồm:
 
 # @@ is the same static variable in Java
 @@y=1
 #self define Class scope
 def self.get_y
    @@y
  end
- Những thành phần lằm trong Object scope bao gồm:
 
    attr_accessor :x
    def get_y
      @@y
    end
- 
Chú ý :Vùng nhớ cấp cho Class scope là một vùng nhớ chia sẻ cho tất cả các Object của nó. Vì thế khi tạo nhiều Object của class Test thì tất cả các object này đều dùng chung biến@@y. - 
@@ycũng là biến tĩnh trong java
 - 
t1, t2, t3 đều dùng chung biến @@y vì @@y nằm trong Class Scope
 
Chứng minh:
    class Test
      @@y = 2
      def get_y
       @@y
      end
    end
    t1 = Test.new
    t2 = Test.new
    t3 = Test.new
    p "@@y in t1: #{t1.get_y}"
    p "@@y in t2: #{t2.get_y}"
    p "@@y in t3: #{t3.get_y}"
Kết quả:
$ @@y in t1: 2
$ @@y in t2: 2
$ @@y in t3: 2
4. Meta-programming (Writing code dynamically)
- Chắc hẳn hầu hết chúng ta đều đã nghe nói tới khái niệm 
Metaprogramming. Hiểu một cách đơn giản thìMetaprogramminglà một kĩ thuật cho phép một ta code ra một ứng dụng mà chính ứng dụng đó quản lý chính bản thân nó.Metaprogramminglà một kĩ thuật cho phép viết code để quản lý code.Metaprogrammingviết code để sinh ra những code khác, viết code để điều khiển những code khác. Ví dụ
 
    class A
      METHOD_NAMES =
      METHOD_NAMES.each do |name|
        define_method(name) do |arg|
          "Called method #{name} with argument: #{arg}"
        end
      end
    end
obj = A.new
obj.abc(42)        # => "Called method abc with argument: 42"
obj.mno('arg')     # => "Called method mno with argument: arg"
Tuy ta không định nghĩa ra các hàm như 'abc', 'def', 'ghi', 'jkl', 'mno', nhưng với Metaprogramming cụ thể là việc sử dụng method define_method ta sẽ dùng code để tạo ra những hàm đó.
    METHOD_NAMES.each do |name|
      define_method(name) do |arg|
        "Called method #{name} with argument: #{arg}"
      end
    end
Please sử dụng define_method hay Metaprogramming với sự cẩn trọng, nhìn về mặt tốt thì bạn có thể thấy nó khá thú vị khi viết ít line hơn mà lại được nhiều code hơn, nhưng sẽ rất không ổn, phức tạp và khó khăn khi bạn thực hiện debug.
5. Modules
- Có một người nói với em là "Ruby’s modules are perhaps one of the language’s most powerful features", em hiểu là : "Modules trong Ruby có lẽ chính là một trong những điểm mạnh nhất của nó"
 - Là một trường hợp đặc biệt của class (nó là một class dặc biệt)
 - Một Module là nơi chứa các 
methodvà cácconstants. - Method trong Module có thể là 
instance methodshoặcmodule methods - Sự khác biệt giữa 
ModulevớiClass- Class là object
 - Module là function
 
 - Mục đích của module là gì
- Module bao gồm những Method mang tính 
chất dùng chung(share) mà nhiều class đều cần sử dụng. Khi nghĩ tới Module có thể hiểu nó như là một nơi đểshare methods. - Đóng vai trò như một 
namespacedùng để gói các class liên quan lại với nhau. - Xử lý việc Dupplicate code, ví dụ bạn có 2 model chứa 2 scope tương tự như:
scope :newest, ->{order("created_at DESC")} - lúc này cách xử lý là tạo ra một module chung (trong Rails ActiveSupport::Concern) và include module trong 2 model để sự dụng chung scope "newest"
 
 - Module bao gồm những Method mang tính 
 - Không thể tạo Instance của module , vì vậy có thể coi Module giống static class trong Java mọi thứ trong module đều được access qua chính tên Module
 
Module vs Class
Khác biệt giữa include và extend trong Ruby?
    module M
      def mod_method
        "Module method invoked"
      end
    end
    class A
      extend M
    end
    class B
      include M
    end
    A.mod_method        # => "Module method invoked"
    B.new.mod_method    # => "Module method invoked"
extend: mixes in specified module methods as class methods in the target classextend: mang những method củamodulevề làmclass methodtrong class
include: mixes in specified module methods as instance methods in the target classinclude: mang những method của module về làm instance method trong class
Tip: Chúng ta có thể include or extend một module bằng cách thứ 2
    module M
      def mod_method
        "Module method invoked"
      end
    end
    class A
    end
    class B
    end
    A.extend M
    B.include M
    A.mod_method        # => "Module method invoked"
    B.new.mod_method    # => "Module method invoked"
6. Hook Methods
What is a Hook Method?
Hook methodslà những phương thức đặc biệt của Ruby cung cấp một cách để mở rộng hoạt động của chương trình tại thời điểm runtime.Hook methodgiống như việc đăng kí (registry) một sự kiện và sự kiện đó sẽ được callback (fire) bởi một chỗ khác.- Câu hỏi:
- Khi bạn kế thừa một class cha từ một class con vậy bên trong việc kế thừa đó chuyện gì sẽ xảy, có hàm nào được thực thi không? hay đơn giản chỉ là từ class con có thể nhìn thấy mọi thứ của class cha.
 
 - Trả lời:
- Khi trình biên dịch đọc đến dòng code mà thấy có sự kết thừa thì nó sẽ callback đến một hàm của class cha, hàm đó chính là một 
hook method 
 - Khi trình biên dịch đọc đến dòng code mà thấy có sự kết thừa thì nó sẽ callback đến một hàm của class cha, hàm đó chính là một 
 - Chúng ta sẽ tìm hiểu về những hook methods bên dưới:
- inherited
 - included
 - extended
 - prepended
 - method_missing
 
 
Inherited
- Inheritance là một khái niệm rất cơ bản và quan trọng trong object-oriented programming.
 - Cú pháp để inherite trong Ruby là kí tự < (class A < B end)
 - Chúng ta sẽ tạo ra 2 class tên là Person và User, User sẽ kế thừa class Person vậy ngoài việc instance của class User sẽ nhìn thấy các method trong class Person, có còn điều gì xảy ra không ?
 - Khi trình biên dịch đọc đến kí tự inherite "<" nó sẽ tự thực hiện việc callback tới phương thức "self.inherited" của class cha
 
    class Person
      def self.inherited child_class
        puts "#{child_class} inherits #{self}"
      end
      def name
        "My name is Person"
      end
    end
    class User < Person
    end
# => User inherits Person
included
includemang tất cả những method của module về làm 'instance method' của class.- Tương tự inherite từ một class ta 
includemột module lúc này khi trình biên dịch đọc đến kí tự include thì nó sẽ callback tớimethod self.includedcủa module cha 
extended
extendemang tất cả những method của module về làm 'class method' của class.- Tương tự inherite từ một class ta 
extendemột module lúc này khi trình biên dịch đọc đến kí tự extended thì nó sẽ callback tới methodself.extendedcủa module cha. 
    module Person
      def self.extende base
        puts "#{base} extended #{self}"
      end
    end
    class User
      extende Person
    end
    # => User extende Person
method_missing
- Là một hook được sử dụng rộng rãi nhất trong Ruby hook method_missing được callback khi một object gọi tới một method không tòn tại.
 - method_missing nhận đầu vào là 2 tham số :
- tham số thứ nhất : tên của method được gọi
 - tham số thứ hai : các tham số được truyền cho method được gọi.
 
 
    class Person
      def method_missing(sym, *args)
        "#{sym} not defined on #{self}"
      end
      def name
        "My name is Person"
      end
    end
    p = Person.new
    puts p.name     # => My name is Person
    puts p.address  # => address not defined on #<Person:0x007fb2bb022fe0>
7. Super basic memoization
||=
- a ||= b tương dương a = a || b
- x || y => return x
 - x && y => return y
 
 
class < < self
- Is another way of defining class methods in Ruby
 
    class << self
      def class_method
      end
    end
    # tương đương với
    class
      def self.class_method
      end
    end
All rights reserved