12/08/2018, 14:41

Một số tính năng hữu ích trong ruby

Có thể nhiều người biết đến Enumerator.new nhưng số người thực sự dùng nó là không nhiều Dưới đây là những lí do nên dùng nó Đưa vào scope mới Producer-Consumer pattern. Làm rõ ràng 2 phase khởi tạo giá trị và sử dụng các giá trị đó Việc đưa toàn bộ giá trị vào 1 mảng tốn memory. Việc dùng ...

Có thể nhiều người biết đến Enumerator.new nhưng số người thực sự dùng nó là không nhiều Dưới đây là những lí do nên dùng nó

  • Đưa vào scope mới
  • Producer-Consumer pattern. Làm rõ ràng 2 phase khởi tạo giá trị và sử dụng các giá trị đó
  • Việc đưa toàn bộ giá trị vào 1 mảng tốn memory. Việc dùng enumerable giúp giảm bớt memory
  • Có thể thực hiện nested

Ví dụ

Producer phase

user_ids = Enumerator.new do |y|
  open("candidates.txt") do |f|
    f.each_line do |line|
      next if line.start_with?("#")
      user_id = line.chomp
      y << user_id
    end
  end
end

Consumer phase

user_ids.with_index 1 do |user_id, index|
  puts "#{index} #{user_id}"
end

Trong ví dụ trên consumer phase là khá đơn giản nên có thể viết trực tiếp, khi nó trở nên phức tạp hơn thì bạn sẽ thấy được lợi ích của việc có thể nested khi sử dụng Enumerator.new

Object#tap có lẽ cũng được nhiều người biết đến nhưng có lẽ chủ yếu dùng để debug trong method chain.

Ví dụ

(1..10).tap { |x| puts "original: #{x.inspect}" }.to_a.
    tap    { |x| puts "array: #{x.inspect}" }.
    select { |x| x%2 == 0 }.
    tap    { |x| puts "evens: #{x.inspect}" }.
    map    { |x| x*x }.
    tap    { |x| puts "squares: #{x.inspect}" }

Kết quả

original: 1..10
array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens: [2, 4, 6, 8, 10]
squares: [4, 16, 36, 64, 100]
=> [4, 16, 36, 64, 100]

Object# tap có thể sử dụng trong nhiều tình huống khác nhau như dưới đây

  • Làm rõ ràng phase khởi tạo biến số và phase sử dụng
  • Khi gía trị trả về là hash hay object và cảm thấy nghi hoặc
alphabet_nums = {}.tap do |hash|
  ("a".."z").each.with_index 1 do |alphabet, index|
    hash[alphabet] = index
  end
end
alphabet_nums = {}
("a".."z").each.with_index 1 do |alphabet, index|
  alphabet_nums[alphabet] = index
end

Khi so sánh 2 cách viết trên, cách viết bọc đoạn code trong tap sẽ làm rõ hơn phase khởi tạo giá trị chính là đoạn code nằm trong tap. Trong trường hợp alphabet_nums không có thay đổi gì sau khi khởi tạo thì có nghĩa là mọi thay đổi của alphabet_nums chỉ nằm trong khối block khởi tạo ban đầu

Trong Ruby có giá trị Float::INFINITY dùng để biểu diễn giá trị vô hạn

Xem xét trường hợp dưới đây

# Nếu to là nil thì giá trị của x lớn bao nhiêu cũng được ngược lại chỉ lấy các giá trị x < to
if to.nil? || x < to
  do_something(x)
end

Bằng cách chuyển giá trị mặc định của to thành Float::INFINITY chúng ta có thể bỏ được đoạn check nil

to ||= Float::INFINITY
if x < to
  do_something(x)
end

Nếu chỉ có 1 đoạn code đơn lẻ như trên thì cũng không thấy được sự tiện lợi, nhưng nếu có nhiều đoạn xử lí với cùng đoạn check điều kiện như trên thì bạn sẽ tránh được việc phải viết đi viết lại đoạn check nil nhiều lần

ruby có cung cấp standard library tên là shellwords

Sau khi require shellwords, các kí tự cần escape trong lệnh bash sẽ tự động được escape và liên kết lại

require 'shellwords'
["vlc", "Ruby on Rails.mp4"].shelljoin #=> "vlc Ruby on Rails.mp4"

Điều này rất thuận tiện khi thực hiện call các lệnh bash tại code ruby

Khi cần tạo chuỗi kí tự ngẫu nhiên (session key chẳng hạn), thực hiện require securerandom sau đó gọi SecureRandom.hex là rất tiện lợi

require 'securerandom'
SecureRandom.hex # "396bc8f76cffce4d3bfea3d07f58b09b"

Ngoài ra còn có thể dùng khi tạo mail ngẫu nhiên, đặt tên cho các file tạm thời

Bằng cách sử dụng cú pháp .. trong câu điều kiện, toán tử này cho phép xác định điều kiện bắt đầu và điều kiện kết thúc

(1..5).each do |x|
  puts x if (x == 2) .. (x == 4)
end

Kết quả là

2
3
4

Một ví dụ khác: thực hiện xử lí chỉ với phần code ruby nằm trong file Markdown. Đoạn code sẽ nằm trong khối bắt đầu và kết thúc với ```

ARGF.each_line do |line|
  if (line.start_with?("```rb"))..(line.chomp == "```")
    do_something(line)
  end
end

http://qiita.com/cuzic/items/a265f140fdff289d5c07 http://ruby-doc.org/core-2.2.0

0