12/08/2018, 17:12

Để có 1 dòng code Ruby đẹp

Ruby là một ngôn ngữ lập trình đẹp. Ruby là một "ngôn ngữ lập trình mã nguồn mở tập trung vào sự đơn giản và hiệu quả. Nó có cú pháp tự nhiên, dễ đọc và dễ viết " được tạo ra bởi Matz , một kỹ sư phần mềm Nhật Bản. Matz thường nói rằng ông "đang cố gắng làm cho Ruby tự nhiên, nhưng nó không ...

Ruby là một ngôn ngữ lập trình đẹp.

Ruby là một "ngôn ngữ lập trình mã nguồn mở tập trung vào sự đơn giản và hiệu quả. Nó có cú pháp tự nhiên, dễ đọc và dễ viết " được tạo ra bởi Matz , một kỹ sư phần mềm Nhật Bản.

Matz thường nói rằng ông "đang cố gắng làm cho Ruby tự nhiên, nhưng nó không đơn giản " phản chiếu cuộc sống của chúng ta.

Ruby nhìn thì đơn giản, nhưng bên trong lại rất phức tạp, giống như cơ thể của chúng ta vậy - Matz

Tôi thấy Ruby là một ngôn ngữ lập trình phức tạp, nhưng rất tự nhiên, có cú pháp đẹp và trực quan. Để thể hiện điều này, tôi lấy vài ví dụ về cách xử lý trong mảng.

Map

Map "trả về một mảng mới với kết quả sau khi chạy một khối mã cho mỗi phần tử trong enum" . Ví dụ: an_array.map { |element| element * element }

Nhìn thật đơn giản! Nhưng khi bạn mới làm quen với ruby, tôi cá là bạn sẽ sử dụng vòng lặp:

user_ids = []
users.each { |user| user_ids << user.id }

Cách đơn giản hơn để có một dòng code đẹp:

user_ids = users.map { |user| user.id }

Hoặc thậm chí đẹp hơn (và nhanh hơn):

user_ids = users.map(&:id)

Select

Khi dùng map, đôi khi code của bạn nhìn như sau:

even_numbers = [1, 2, 3, 4, 5].map { |element| element if element.even? } # [ni, 2, nil, 4, nil]
even_numbers = even_numbers.compact # [2, 4]

Dùng map để chọn các số chẵn nhưng cũng trả về đối tượng nil . Vì vậy, bạn sử dụng compact để loại bỏ tất cả các đối tượng nil .

Come on, có thể làm tốt hơn với select:

[1, 2, 3, 4, 5].select { |element| element.even? }

Chỉ cần một dòng đơn giản, dễ hiểu.

Bonus :

[1, 2, 3, 4, 5].select(&:even?)

Sample

Bạn cần lấy một phần tử ngẫu nhiên từ một mảng. Bạn chỉ mới bắt đầu học ruby, vì vậy suy nghĩ đầu tiên của bạn sẽ là dùng random, và code ra thế này:

[1, 2, 3][rand(3)]

Dễ hiểu, nhưng không chắc là nó đủ tốt. Và nếu chúng ta sử dụng shuffle thì sao?

[1, 2, 3].shuffle.first

Hmm. Tôi thực sự thích shuffle thay vì rand . Nhưng khi tôi phát hiện ra sample, nó có ý nghĩa hơn rất nhiều:

[1, 2, 3].sample

Thực sự đơn giản, tự nhiên và trực quan. Chúng ta cần 1 số từ một mảng và phương thức sample trả về nó.

Như tôi đã đề cập trước đây, tôi thích cách code trong Ruby. Nó tự nhiên như trong ví dụ dưới đây.

Return

Bất kỳ một phương thức nào trong ruby đều trả về giá trị của biểu thức cuối cùng trong method đó. Ví dụ tôi gọi một phương thức và mong đợi một số giá trị trả về:

def get_user_ids(users)
  return users.map(&:id)
end

Nhưng như đã biết, ruby luôn trả về giá trị của biểu thức cuối cùng, vậy tại sao phải sử dụng return?

def get_user_ids(users)
  users.map(&:id)
end

Từ khi biết điều này, tôi sử dụng hầu hết các phương thức mà không cần return.

Multiple Assignments

Ruby cho phép gán nhiều biến cùng lúc. Khi mới bắt đầu, bạn có thể code thế này:

def values
  [1, 2, 3]
end

one   = values[0]
two   = values[1]
three = values[2]

Sao không chỉ định nhiều biến cùng lúc?

def values
  [1, 2, 3]
end

one, two, three = values

Tuyệt vời!

Phương thức dạng câu hỏi

Một trong số các tính năng thú vị trong Ruby là phương thức dạng câu hỏi. Bạn có thể code thế này: movie.awesome # => true

Ok ... không sai. Nhưng thử sử dụng dấu hỏi:

movie.awesome? # => true

Nhìn diễn cảm hơn và thể hiện rằng phương thức trả về sẽ có giá trị true/false.

Tôi hay sử dụng any?. Nó check xem một mảng có phần tử nào thoả mãn điều kiện hay không.

[].any? # => false
[1, 2, 3].any? # => true

Interpolation

Đối với tôi, chuỗi interpolation trực quan hơn so với chuỗi concatenation.

Ví dụ chuỗi concatenation:

programming_language = "Ruby"
programming_language + " is a beautiful programming_language" # => "Ruby is a beautiful programming_language"

Chuỗi interpolation:

programming_language = "Ruby"
"#{programming_language} is a beautiful programming_language" # => "Ruby is a beautiful programming_language"

Tôi thích interpolation. Còn bạn?

If

Một cách tôi thực sự thích khi sử dụng lệnh If:

def hey_ho?
  true
end

puts "let’s go" if hey_ho?

Nhìn thật tự nhiên.

Try

Khi try một phương thức hoặc thuộc tính nào đó của 1 object, nếu object đó không tồn tại thì sẽ trả về nil .

Sử dụng if/unless:

user.id unless user.nil?

Sử dụng try:

user.try(:id)

Từ Ruby 2.3, chúng ta có thể sử dụng toán tử &. thay cho try:

user&.id

Double Pipe Equals/Memoization

Tính năng này rất tuyệt! Nó giống như việc lưu trữ một giá trị trong một biến.

some_variable ||= 10
puts some_variable # => 10

some_variable ||= 99
puts some_variable # => 10

Bạn không cần phải sử dụng khai báo nào cả. Chỉ cần ||= và nó được thực hiện! Đơn giản và dễ dàng.

Class Static Method

Tôi muốn tạo một "static method" (class method).

GetSearchResult.call(params)

Đơn giản. Đẹp. Trực quan. Điều gì xảy ra đằng sau?

class GetSearchResult
  def self.call(params)
    new(params).call
  end

  def initialize(params)
    @params = params
  end

  def call
    # ... your code here ...
  end
end

Phương thức self.call khởi tạo một thể hiện và đối tượng này là phương thức call.

Getters & Setters

Với class GetSearchResult , nếu muốn sử dụng params, chúng ta có thể sử dụng các params @.

class GetSearchResult
  def self.call(params)
    new(params).call
  end

  def initialize(params)
    @params = params
  end

  def call
    # ... your code here ...
    @params # do something with @params
  end
end

Định nghĩa một setter/getter cho biến instance này.

class GetSearchResult
  def self.call(params)
    new(params).call
  end

  def initialize(params)
    @params = params
  end

  def call
    # ... your code here ...
    params # do something with params method here
  end

  private

  def params
    @params
  end

  def params=(parameters)
    @params = parameters
  end
end

Hoặc có thể khai báo attr_reader , attr_writer hoặc attr_accessor.

class GetSearchResult
  attr_reader :param

  def self.call(params)
    new(params).call
  end

  def initialize(params)
    @params = params
  end

  def call
    # ... your code here ...
    params # do something with params method here
  end
end

Không cần phải định nghĩa các phương thức getter và setter. Code trở nên thật đơn giản.

Tap

Ví dụ phương thức create_user thiết lập các thông số, lưu và trả lại new user.

def create_user(params)
  user       = User.new
  user.id    = params[:id]
  user.name  = params[:name]
  user.email = params[:email]
  # ...
  user.save
  user
end

Không có gì sai ở đây. Nhưng nếu sử dụng phương thức tap.

def create_user(params)
  User.new.tap do |user|
    user.id    = params[:id]
    user.name  = params[:name]
    user.email = params[:email]
    # ...
    user.save
  end
end

Chỉ cần quan tâm đến các tham số, và phương thức tap sẽ trả về đối tượng người dùng cho bạn.

Happy Coding!

Nguồn: Medium

0