Ruby không ngừng ra các phiên bản mới cụ thể gần đây nhất 12/2019 Ruby đã ra phiên bản 2.7 Đây là phiên bản cuối cùng của phiên bản 2.x của Ruby trước khi ra phiên bản 3.0. Cùng nhìn lại xem phiên bản này có gì mới nhé :D

Enumerable#tally

Để đếm số phần tử trong mảng ta thường làm thủ công bằng các cách như sau :

array
  .group_by { |v| v }
  .map { |k, v| [k, v.size] }
  .to_h
  
array
  .group_by { |v| v }
  .transform_values(&:size)

array.each_with_object(Hash.new(0)) { |v, h| h[v] += 1 }

Ở phiên bản 2.7 ta có thể dùng tally.

tally là method đếm các phần tử trong mảng rồi trả về dưới dạng hash có key : phần tử trong mảng, value là số lần xuất hiện.

Ví dụ :

["A", "B", "C", "B", "A"].tally 

Kết quả

{"A"=>2, "B"=>2, "C"=>1}

Enumerable#filter_map

selectmap thường dùng kết hợp để chuyển đổi 1 mảng thành 1 mảng khác với các điều kiện.

VD: Chọn các số lẻ có trong mảng rồi trả về kết quả 1 mảng dưới dạng String ta có các cách như sau:

[1, 2, 3].select { |x| x.odd? }.map { |x| x.to_s }
[1, 2, 3].map { |x| x.to_s if x.odd? }.compact 
[1, 2, 3].each_with_object([]) { |x, m| m.push(x.to_s) if x.odd? }

filter_map đã giúp chúng ta giải quyết vde này 1 cách nhanh chóng, quá tiện lợi:

[1, 2, 3].filter_map {|x| x.odd? ? x.to_s : nil } #=> ["1", "3"]

filler_map không hẳn giống map + compact vì nó loại bỏ cả giá trị false, còn compact thì không, Compact chỉ loại bỏ nil

Numbered Parameters

Nhìn vào ví dụ ta có 1 block với 1 tham số n:

[1,2,3].each { |n| puts n }

n là tham số và ta phải define thì mới dùng được

Nếu n là 1 tham số mặc định, k cần define mà vẫn dùng dc thì dòng code của chúng ta sẽ ngắn gọn đi rất nhiều.

Ruby 2.7 đã làm dc điều đó. Đoạn code trên có thể thay thế bằng :

[1,2,3].each { puts _1 }

_1 là tham số đầu tiên, tương tự _n với tham số thứ n

Tham khảo thêm cách dùng với _n :

# bad
names.map { |name| name.upcase }
# good
names.map(&:upcase)
# also good?
names.map { _1.upcase }

Với 2 tham số thì sẽ dùng ntn:

hash = {
  key_1: "1",
  key_2: "2",
}

# bt sẽ là :
hash.map{|key, value| [key.to_s, value.to_i]}.to_h

# Sử dụng tham số mặc định :
hash.map { [_1.to_s, _2.to_i] }.to_h 
# => { "key_1" => 1, "key_2" => 2 }

Array#intersection

Để tìm các phần tử có ở cả 2 mảng ta hay dùng :

[ 1, 1, 3, 5 ] & [ 3, 2, 1 ]                 #=> [ 1, 3 ]
[ 'a', 'b', 'b', 'z' ] & [ 'a', 'b', 'c' ]   #=> [ 'a', 'b' ]

Giờ chúng ta có thể dùng intersection để trả về kết quả trùng nhau giữa 2 mảng

[ 1, 1, 3, 5 ].intersection([ 3, 2, 1 ])                #=> [ 1, 3 ]
[ 'a', 'b', 'b', 'z' ].intersection([ 'a', 'b', 'c' ])  #=> [ 'a', 'b' ]

Nhớ lại 1 chút nếu làm việc vs 2 mảng ta có thể sử dụng các method sau :

Short Version Long version Mục đích
& intersection Lấy về kết quả trùng nhau giữa 2 mảng
I union Trả về mảng mới, k bao gồm các phần tử trùng lặp và giữ nguyên vị trí các phần tử trong mảng
difference Lấy về kết quả khác nhau giữa 2 mảng

Argument forwarding syntax

Chúng ta có thể sử dụng syntax (...) để thêm toàn bộ tham số của method vào 1 method khác dc gọi bên trong.

VD:

def add(a, b)
  a + b
end

def add_and_double(...)
  add(...) * 2
end

add_and_double(2, 3) #=> 10

Pattern matching

Dùng in Chúng ta có thể so sánh pattern matching giống như regex VD:

[1,2,3] in [a,b,c] # true
[1,2,3] in [a]     # false

[a,b,c] đại diện cho mảng có 3 phần tử. ở đây check [1,2,3] có phải là mảng có 3 phần tử k. ta có thể thay thê a,b,c bằng c,d,f

Ngoài check trên array ta có thể check trên hash :

{ a: 1, b: 2, c: [] } in { a: a, b: b, c: [] }
# true
p a
# 1

{ a: 1, b: 2, c: [] } in { a: a, b: b}
# false

Beginless Ranges

Khi sử dụng case when với nhiều điều kiện sẽ có trường hợp ta phải xử lý trường hợp 1 đầu vô hạn như : in ra là quá khứ nếu date <= current date, lớn hơn >= current date in ra là tương lai, các trường hợp còn lại in ra là hiện tại ta có thể làm như sau :

case date
when ..Date.today
  :past
when Date.today..
  :feture
else
  :now
end

1 ví dụ khác

case release_date
when ..1.year.ago 
  puts "ancient"
when 1.year.ago..3.months.ago
  puts "old"
when 3.months.ago..Date.today
  puts "recent"
when Date.today..
  puts "upcoming"
end

Gọi private method bằng self

Ở các phiên bản trước đó ta k thể gọi self.private_method mà chỉ có thể gọi self.public_method hoặc self.protected_method Ở phiên bản 2.7 đã nâng cấp phạm vi truy cập của private : ta đã có thể gọi self.private_method

Giao diện IRB được nâng cấp

IRB hỗ trợ highlight cú pháp. tự động thụt dòng khi code xuống dòng hỗ trợ auto completion rất tiện lợi khi code trực tiếp trên irb. So vs các phiên bản trc đó thì nó dc hỗ trợ về mặt giao diện rất nhiều nhưng vẫn đi sau thằng Pry

Ref:

https://www.rubyguides.com/2019/12/ruby-2-7-new-features/

https://medium.com/rubyinside/whats-new-in-ruby-2-7-79c98b265502