“Ruby có ngoại hình đơn giản, nhưng có tâm hồn rất phức tạp giống như con người chúng ta vậy.” – Matz, cha đẻ của ngôn ngữ lập trình Ruby.
Vì sao bạn nên học Ruby?
Đối với tôi, Ruby là một ngôn ngữ đẹp. Bạn sẽ thấy việc viết code trong Ruby rất mượt mà và tự nhiên.
Mặt khác, một trong những nguyên nhân khiến cho Ruby nổi tiếng nằm ở Rails: một framework được dùng bởi Twitter, Basecamp, Airbnb, Github, và nhiều công ty khác.
Nguồn gốc
Ruby là một ngôn ngữ lập trình open source vô cùng mạnh mẽ với sự đơn giản mà hiệu quả. Với các cú pháp đầy thanh lịch giúp cho việc đọc và viết vô cùng dễ dàng.
Hãy bắt đầu với nền tảng của Ruby
Tham khảo thêm các vị trí tuyển dụng Ruby lương hấp dẫn trên TopDev
Variables
Bạn có thể hiểu đơn giản rằng một variable là một từ chứa một giá trị. Đơn giản thế thôi.
Trong Ruby, rất dễ để ta define một variable và cho nó một giá trị. Giả sử bạn muốn cho giá trị là 1 vào một variable với tên gọi cũng là một.
one = 1
Quá dễ đúng không?
two = 2 some_number = 10000
Bạn có thể cho bất kì giá trì gì mình muốn cho variable mà bạn thích. Trong ví dụ trên, variable tên là two chứa giá trị 2 và variable tên là some_number có giá trị 10,000.
Ngoài integers, ta còn có thể dùng booleans (true/false), strings, symbols, float, và các dạng data types khác.
# booleans true_boolean = true false_boolean = false # string my_name = "Leandro Tk" # symbol a_symbol = :my_symbol # float book_price = 15.80
Conditional Statements: Điều khiển Flow
Conditional statements sẽ có nhiệm vụ xem xét tính true/false của một statement. Nếu kết quả là True (Đúng), thì nội dung bên trong sẽ được xử lí.
if true puts "Hello Ruby If" end if 2 > 1 puts "2 is greater than 1" end
Bởi vì 2 lớn hơn 1 nên dòng chữ “2 is greater than 1” sẽ được hiện ra.
Else statement sẽ được thực hiện khi ta gặp kết quả False(Sai):
if 1 > 2 puts "1 is greater than 2" elsif 2 > 1 puts "1 is not greater than 2" else puts "1 is equal to 2" end
Bởi 1 không lớn hơn 2, nên code trong Else statement sẽ được xử lí.
Ngoài ra thì bạn cũng có thể dùng tới elsif statement, vốn kết hợp cả 2 loại trên:
if 1 > 2 puts "1 is greater than 2" elsif 2 > 1 puts "1 is not greater than 2" else puts "1 is equal to 2" end
Tôi thì lại thích dùng if statement sau khi code đã được thực hiện:
def hey_ho? true end puts "let’s go" if hey_ho?
Nhìn rất đẹp mà lại ngắn gọn. Đó là thế mạnh của Ruby.
Tham khảo tuyển dụng ruby on rails lương cao trên TopDev
Looping/Iterator
Trong Ruby, chúng ta có thể iterate bằng nhiều hình thức khác nhau: while, for và each.
Vòng lặp While: Miễn là kết quả của statement vẫn là true, nội dung code nằm trong statement sẽ luôn được thực hiện. Như vậy, Code sẽ in và hiển thị từ số 1 tới 10 trong ví dụ dưới đây:
num = 1 while num <= 10 puts num num += 1 end
Vòng lặp For: Với Statement được cho ra, nội dung code sẽ được thực hiện cho đến khi thõa mãn yêu cầu của statement đó.
for num in 1...10 puts num end
Each iterator: Với bất kì array của giá trị, nó sẽ iterate từng giá trị một.
[1, 2, 3, 4, 5].each do |num| puts num end
Điểm khác biết giữa For và Each là Each thực hiện chính xác từng giá trị được cho trong khi For sẽ xuất hiện những giá trị không mong muốn nằm ngoài yêu cầu.
# for vs each # for looping for num in 1...5 puts num end puts num # => 5 # each iterator [1, 2, 3, 4, 5].each do |num| puts num end puts num # => undefined local variable or method `n' for main:Object (NameError)
Array: Collection/List/Data Structure
Giả sử như bạn muốn lưu integer 1 vào một variable. Nhưng giờ thì bạn muốn lưu 2, và rùi 3,4,5….
Vậy có cách nào để có thể lưu những integers mà bạn muốn mà không phải cứ làm cách thủ công như vậy. Ruby sẽ cung cấp giải pháp cho bạn.
Array là một collection dùng để lưu trữ một list các values.
my_integers = [1, 2, 3, 4, 5]
Rất là đơn giản, chúng ta tạo ra một array và lưu nó vào my_integer.
Bạn sẽ tự hỏi rằng “làm cách nào để lấy giá trị từ array đó?”. Trong Arrays có một khái niệm gọi là Index. Bắt đầu với index 0 và cứ thể tăng dần lên.
Sử dụng cú pháp Ruby, nó rất đơn giản để hiểu:
my_integers = [5, 7, 1, 3, 4] print my_integers[0] # 5 print my_integers[1] # 7 print my_integers[4] # 4
Giờ nếu bạn muốn lưu strings thay vì integers, đại loại như list tên họ hàng của bạn chẳng hạn:
relatives_names = [ "Toshiaki", "Juliana", "Yuji", "Bruno", "Kaio" ] print relatives_names[4] # Kaio
Không có gì khác ngoài trừ giờ ta dùng chữ thay cho số.
Giờ khi nói về array data structure, ta ám chỉ việc đụng tới các giá trị trong array đó.
Phương pháp thường thấy dùng để thêm giá trị vào array là push và <<.
Push cực kì đơn giản, như ví dụ sau đây:
bookshelf = [] bookshelf.push("The Effective Engineer") bookshelf.push("The 4 hours work week") print bookshelf[0] # The Effective Engineer print bookshelf[1] # The 4 hours work week
Phương pháp << thì có chút khác biệt với:
bookshelf = [] bookshelf << "Lean Startup" bookshelf << "Zero to One" print bookshelf[0] # Lean Startup print bookshelf[1] # Zero to One
Bạn có thể thấy sự khác biệt nằm ở dấu chấm. Có thể nói:
bookshelf << "Hooked"
Cũng chính là
bookshelf.<<("Hooked")
Ruby thật là tuyệt đúng không?
Giờ hãy nói thêm về một loại Data Structure khác.
Hash: Key-Value Data Structure/Dictionary Collection
Chúng ta đều đã biết arrays thực chất chính là array với số. Thế nhưng nếu chúng ta dùng số thứ tự thì sao? Một số data structures có thể dùng số, string, hoặc các dạng type khác. Hash data structure là một trong số đó.
Hash là một collection các cặp key-value:
hash_example = { "key1" => "value1", "key2" => "value2", "key3" => "value3" }
Trong đó, Key sẽ ám chỉ index của value. Vậy để truy cấp vào value của Hash thì ta sẽ thông qua Key.
Sau đây là một hash về tôi với Key là họ tên, nickname, sắc tộc:
hash_tk = { "name" => "Leandro", "nickname" => "Tk", "nationality" => "Brazilian" } print "My name is #{hash_tk["name"]}" # My name is Leandro print "But you can call me #{hash_tk["nickname"]}" # But you can call me Tk print "And by the way I'm #{hash_tk["nationality"]}" # And by the way I'm Brazilian
Trong ví dụ trên, tôi cho in ra mọi thông tin về mình.
Một điều khá tuyệt của hash là chúng ta có thể dùng bất cứ thứ gì làm value. Tôi sẽ thêm key “age” và số tuổi của mình là 24 vào value.
hash_tk = { "name" => "Leandro", "nickname" => "Tk", "nationality" => "Brazilian", "age" => 24 } print "My name is #{hash_tk["name"]}" # My name is Leandro print "But you can call me #{hash_tk["nickname"]}" # But you can call me Tk print "And by the way I'm #{hash_tk["age"]} and #{hash_tk["nationality"]}" # And by the way I'm 24 and Brazilian
Giờ chúng ta sẽ thêm các nhân tố khác vào một hash. Key dẫn tới value chính là đặc điểm làm nên Hash nên việc thêm vào cũng sẽ theo qui luật như vậy.
hash_tk = { "name" => "Leandro", "nickname" => "Tk", "nationality" => "Brazilian" } hash_tk["age"] = 24 print hash_tk # { "name" => "Leandro", "nickname" => "Tk", "nationality" => "Brazilian", "age" => 24 }
Bạn có thấy việc thêm một giá trị vào hash rất đơn giản đúng không?
Iteration: Vòng lặp thông qua Data Structures
Array iteration thật sự rất đơn giản. Ruby developer thường dùng each iterator:
bookshelf = [ "The Effective Engineer", "The 4 hours work week", "Zero to One", "Lean Startup", "Hooked" ] bookshelf.each do |book| puts book end
Each iterator ở trên hoạt động bằng cách đi qua từng yếu tố trong array như là một thông số. Trong ví dụ trên, chúng ta sẽ in ra từng yếu tố đó.
Với hash data structure, ta cũng có thể dùng each iterator để đi qua 2 thông số trong cùng một block: key và value.
hash = { "some_key" => "some_value" } hash.each { |key, value| puts "#{key}: #{value}" } # some_key: some_value
Ta sẽ đặt tên cho hai tham số này là key và value cho khỏi bị nhầm lẫn.
hash_tk = { "name" => "Leandro", "nickname" => "Tk", "nationality" => "Brazilian", "age" => 24 } hash_tk.each do |attribute, value| puts "#{attribute}: #{value}" end
Classes & Objects
Là một ngôn ngữ lập trình object oriented, Ruby dùng class và object.
“Class” là một cách để define objects. Ví dụ như xe ô tô có nhiều loại.
“Objects” có 2 đặc điểm: data và behavior. Ví dụ như ô tô có data về số bánh xe, chiều dài cũng như behavior với khả năng tăng tốc và phanh.
Trong lập trình object oriented, ta gọi data là “attributes” và behavior là “methods.”
Ruby Object Oriented Programming Mode: On
Sau đây là một cú pháp trong Ruby cho Class:
class Vehicle end
Ta define Vehicle với class statement và kết thúc bằng end.
Objects chính là đại diện cho class. Ta tạo ra instance bằng phương pháp .new
vehicle = Vehicle.new
Tại đây, vehicle là object (hay instance) của class: Vehicle
vehicle class có 4 attributes: bánh xe, loại thùng tank, số ghế và vận tốc.
class Vehicle def initialize(number_of_wheels, type_of_tank, seating_capacity, maximum_velocity) @number_of_wheels = number_of_wheels @type_of_tank = type_of_tank @seating_capacity = seating_capacity @maximum_velocity = maximum_velocity end end
Chúng ta đã sử dụng phương pháp initialize (khởi tạo). Với tên gọi khác là constructor bởi khi bạn tạo ra vehicle object, đồng thời ta cũng sẽ define các attributes của nó luôn.
Giả sử bạn rất thích chiếc Tesla Model S và muốn tạo một object như vậy. Bao gồm 4 bánh, là xe điện, 5 chỗ và chạy được với vận tốc tối đa là 250km/hour (155 mph).
tesla_model_s = Vehicle.new(4, 'electric', 5, 250)
4 wheels + electric tank + 5 seats + 250km/hour maximum speed = tesla_model_s.
tesla_model_s # => <Vehicle:0x0055d516903a08 @number_of_wheels=4, @type_of_tank="electric", @seating_capacity=5, @maximum_velocity=250>
Vậy là ta đã set up lên Tesla’s attributes. Nhưng truy cập vào bằng cách nào?
Tất nhiên là bằng cách gửi tin tới object để hỏi về chúng.
class Vehicle def initialize(number_of_wheels, type_of_tank, seating_capacity, maximum_velocity) @number_of_wheels = number_of_wheels @type_of_tank = type_of_tank @seating_capacity = seating_capacity @maximum_velocity = maximum_velocity end def number_of_wheels @number_of_wheels end def set_number_of_wheels=(number) @number_of_wheels = number end end
Trong ví dụ trên, ta dùng hai cách number_of_wheels và set_number_of_wheels. Hay còn được biết tới là getter and setter. Đầu tiên là ta lấy một giá trị với `get`, thứ hai ta có thể đặt ra một giá trị với set.
Trong Ruby, ta có thể dùng những phương pháp trên với attr_reader, attr_writer và attr_accessor.
- attr_reader: áp dụng phương pháp getter
class Vehicle attr_reader :number_of_wheels def initialize(number_of_wheels, type_of_tank, seating_capacity, maximum_velocity) @number_of_wheels = number_of_wheels @type_of_tank = type_of_tank @seating_capacity = seating_capacity @maximum_velocity = maximum_velocity end end tesla_model_s = Vehicle.new(4, 'electric', 5, 250) tesla_model_s.number_of_wheels # => 4
- attr_writer: áp dụng phương pháp setter
class Vehicle attr_writer :number_of_wheels def initialize(number_of_wheels, type_of_tank, seating_capacity, maximum_velocity) @number_of_wheels = number_of_wheels @type_of_tank = type_of_tank @seating_capacity = seating_capacity @maximum_velocity = maximum_velocity end end # number_of_wheels equals 4 tesla_model_s = Vehicle.new(4, 'electric', 5, 250) tesla_model_s # => <Vehicle:0x0055644f55b820 @number_of_wheels=4, @type_of_tank="electric", @seating_capacity=5, @maximum_velocity=250> # number_of_wheels equals 3 tesla_model_s.number_of_wheels = 3 tesla_model_s # => <Vehicle:0x0055644f55b820 @number_of_wheels=3, @type_of_tank="electric", @seating_capacity=5, @maximum_velocity=250>
- attr_accessor: áp dụng cả 2 phương pháp trên
class Vehicle attr_accessor :number_of_wheels def initialize(number_of_wheels, type_of_tank, seating_capacity, maximum_velocity) @number_of_wheels = number_of_wheels @type_of_tank = type_of_tank @seating_capacity = seating_capacity @maximum_velocity = maximum_velocity end end # number_of_wheels equals 4 tesla_model_s = Vehicle.new(4, 'electric', 5, 250) tesla_model_s.number_of_wheels # => 4 # number_of_wheels equals 3 tesla_model_s.number_of_wheels = 3 tesla_model_s.number_of_wheels # => 3
Ngoài ra ta còn có những phương pháp khác như “make_noise” method
class Vehicle def initialize(number_of_wheels, type_of_tank, seating_capacity, maximum_velocity) @number_of_wheels = number_of_wheels @type_of_tank = type_of_tank @seating_capacity = seating_capacity @maximum_velocity = maximum_velocity end def make_noise "VRRRRUUUUM" end end
Khi ta call thì nó sẽ return với một string là “VRRRRUUUUM”.
v = Vehicle.new(4, 'gasoline', 5, 180) v.make_noise # => "VRRRRUUUUM"
Encapsulation: Cất giấu thông tin
Encapsulation là cách giới hạn việc truy cập trực tiếp vào objects’ data đồng thời tạo điều kiện cho hoạt động cho data.
Nói cách khác những thông tin bên trong sẽ được giấu kín.
Như vậy, trong Ruby, ta sẽ dùng một phương pháp để truy cập dữ liệu trực tiếp:
class Person def initialize(name, age) @name = name @age = age end end
Như vậy, ta đã áp dụng Person class.
tk = Person.new("Leandro Tk", 24)
Vậy thì để truy cập được nhưng thông tin này thì phải làm sao? call name và age method?
tk.name > NoMethodError: undefined method `name' for #<Person:0x0055a750f4c520 @name="Leandro Tk", @age=24>
Rõ ràng là không được. Đó là bởi chúng ta phải dùng phương thức truy cập trực tiếp như sau:
class Person def initialize(name, age) @name = name @age = age end def name @name end def age @age end end
Inheritance: behaviors và characteristics
Một số các objects đều có những điểm chung với nhau: Behavior và characteristics.
Hãy thử tưởng tượng một chiếc xe với những attributes như số bánh xe, vận tốc tối đa, etc…
class Car attr_accessor :number_of_wheels, :seating_capacity, :maximum_velocity def initialize(number_of_wheels, seating_capacity, maximum_velocity) @number_of_wheels = number_of_wheels @seating_capacity = seating_capacity @maximum_velocity = maximum_velocity end end
Car class đã được implement 🙂
my_car = Car.new(4, 5, 250) my_car.number_of_wheels # 4 my_car.seating_capacity # 5 my_car.maximum_velocity # 250
Trong Ruby, chúng ta dùng < operator để chỉ định rằng một class được thừa kế từ class khác. Một ElectricCar class sẽ thừa kế từ Car class.
class ElectricCar < Car end
Đơn giản vậy đấy, ta không cần dùng thêm phương pháp nào bởi class này đã có sẵn thông tin được thừa kế từ Car.
tesla_model_s = ElectricCar.new(4, 5, 250) tesla_model_s.number_of_wheels # 4 tesla_model_s.seating_capacity # 5 tesla_model_s.maximum_velocity # 250
Module: Một Toolbox
Chúng ta có thể xem module như một toolbox chứa đựng một set các constants và phương pháp.
Một ví dụ của Ruby module là Math.
Math::PI # > 3.141592653589793
Và phương pháp .sqrt:
Math.sqrt(9) # 3.0
Chúng ta cũng có thể áp dụng module của mình và dùng nó trong class. Ta có một RunnerAthlete class:
class RunnerAthlete def initialize(name) @name = name end end
Và áp dụng module Skill vào để có average_speed
module Skill def average_speed puts "My average speed is 20mph" end end
Vậy làm sao để thêm module vào cho classes để nó có được tính cách trên (average_speed)? Bạn cứ đơn giản là ghi thẳng vào luôn!
class RunnerAthlete include Skill def initialize(name) @name = name end end
Bạn có thể thấy phần “include Skill”! Giờ thì bạn đã có thể xài phương pháp này trong instance của RunnerAthlete class.
mohamed = RunnerAthlete.new("Mohamed Farah") mohamed.average_speed # "My average speed is 20mph"
Tuy vậy bạn cần phải nhớ những điều sau:
- module có thể không có instances
- module có thể không có subclass
- module được define bằng module
Nguồn: blog.topdev.vn via medium
Xem tin tuyển dụng IT lương cao tren TopDev