Ôn thi Ruby Silver v 2.1

Như tiêu đề, mình đang muốn học lại Ruby để 1 là kiếm chứng chỉ Ruby Silver, 2 là bổ sung thêm những phần kiến thức chưa biết về Ruby nên ta có bài này. Ở đây sẽ có ưu ái hẳn hoi 1 bài mẫu luôn để mọi người cũng chiêm ngưỡng. a =[1,2,3,5,8]

Như tiêu đề, mình đang muốn học lại Ruby để 1 là kiếm chứng chỉ Ruby Silver, 2 là bổ sung thêm những phần kiến thức chưa biết về Ruby nên ta có bài này.

Ở đây sẽ có ưu ái hẳn hoi 1 bài mẫu luôn để mọi người cũng chiêm ngưỡng.

a =[1,2,3,5,8]
b =[1,3,6,7,8]
c =false||true?true&&false? a | b : a & b : b ;
p c

Trên đây là cơn choáng mình nhận được vì lỡ học khuya lúc 12 giờ đêm. Và để phân tích nó thì chúng ta sẽ cùng đi lại vài kiến thức Ruby cơ bản.

Enumerable

Các hệ số trong Ruby

Hệ Cú pháp Ví dụ
Nhị phân 0b 0b01 là 1
Bát phân 0o hoặc 0 070 hay 0o70 là 56
Thập phân 0d 0d10 bằng 10
Thập lục phân 0x 0xAB trả về kết quả 171

find_all – select, detect – find, collect – map

  • find_all, select : Trả về tất cả các phần tử của mảng thỏa mãn yêu cầu nào đó
  • detect,find : Trả về giá trị đầu tiên thỏa mãn điều kiện nào đó
  • collect, map: Trả về mảng thỏa mãn điều kiện đã cho

Các toán tử

Toán tử đại số

Toán tử Ý nghĩa Ví dụ
+ Toán tử cộng 10 + 20 trả về 30
Toán tử trừ 10 - 20 trả về -10
* Toán tử nhân 10 * 20 trả về 200
/ Phép chia lấy phần nguyên 20 / 10 trả về 2
% Phép chia lấy phần dư 20 % 10 trả về 0
** Luỹ thừa 10**20 sẽ trả về 102010^{20}

Ví dụ đơn giản:

deffoo(n)
  n ** n
end

puts foo(3)*2

Ta có 33∗23^ 3 * 2 bằng 54.

Toán tử so sánh

Các toán tử này dùng để so sánh giá trị của 2 phần tử

Toán tử Ý nghĩa Ví dụ
== Trả về true nếu bằng nhau 10==10.0 trả về true
!= Trả về true nếu khác nhau 10!=10.0 trả về false
> Trả về true nếu giá trị trước lớn hơn giá trị sau 10>5 trả về true
< Trả về true nếu giá trị trước nhỏ hơn giá trị sau 10<20 trả về true
>= Trả về true nếu giá trị trước lớn hơn hoặc bằng giá trị sau 10>=10.0 trả về true
<= Trả về true nếu giá trị trước nhỏ hơn hoặc bằng giá trị sau 10<=10.0 trả về true
<=> So sánh gộp. 0 nếu bằng nhau, 1 nếu giá trị trước lớn hơn và -1 nếu giá trị trước nhỏ hơn 10<=>20 sẽ trả về -1
=== Cũng là check giá trị bằng nhau như mà nó lạ …. à không lạ lắm. Toán tử này hay dùng trong các câu lệnh điều kiện if-else và case-when 10===10.0 trả về true
eql? Check không chỉ giá trị mà còn kiểu dữ liệu của 2 phần tử so sánh 10.eql?10.0false. Giá trị bằng nhau nhưng type intfloat là khác nhau
equal? Trả về true nếu 2 phần tử có chung object id a="xyz", b="xyz" nhưng a.equal?bfalse

Ví dụ:

  • Cho a = 10, b = 10.0. a==ba===b trả về cùng giá trị true còn a.eql?ba.equal?b cùng là false.

Toán tử gán

Phần này giống với toán tử toán học 1 chút, nên mình sẽ lướt qua. = là gán giá trị, ví dụ a = b là gán giá trị b bằng với a, còn a += b thì tức là a = a + b

Toán tử song song

Thay vì làm như này

a =10
b =20
c =30

Chúng ta có thể gán nhanh như này

a, b, c =10,20,30

Với cách này, ta có thể dùng để hoán đổi giá trị

a, b = b, c

Sự khác nhau của s..es...e

s..e là lấy các phần tử từ s tới cả e, còn s...e là lấy các phần tử từ s tới trước e.

Ví dụ:

  • 10..15[10, 11, 12, 13, 14, 15]
  • 10...15[10, 11, 12, 13, 14]
  • [10..15] tương đương [10, 15]

Toán tử logic

Toán tử Ý nghĩa Ví dụ
&& hay and Toán tử logic AND. Trả về kết quả true khi cả 2 phần tử đều đúng 10 && 20 trả về true
|| hay or Toán tử logic OR. Trả về kết quả true khi cả 1 phần tử đúng 10 || 20 trả về true
! hay not Toán tử logic NOT. Trả về kết quả ngược lại với điều kiện !(10 && 20) sẽ trả về false

Mảng

Các toán tử của mảng

Giao của 2 mảng& :

["a","b","c"]&["c","d","a"]#=> [ "a", "c" ]

Hợp của 2 mảng | :

["a","b","c"]|["c","d","a"]#=> [ "a", "b", "c", "d" ]

Và cái dễ nhầm là đây. PHẢI NHỚ RẰNG 1 DẤU THÌ MỚI CÓ NGHĨA KIA, CÒN 2 DẤU THÌ SẼ KHÁC|| là chỉ lấy mảng trái, không lấy mảng phải

["a","b","c"]||["c","d","a"]#=> [ "a", "b", "c" ]

&& là chỉ lấy mảng phải, không lấy mảng trái

["a","b","c"]&&["c","d","a"]#=> [ "c", "d", "a" ]

slice

# create arrays
array1 =[1,2,3,4,5]
array2 =["a","b","c","d","e"]
array3 =["cat","dog","cow","rat","fox"]
array4 =[true,false,nil]
array5 =["","nil","false","true"]# call `slice()` method and save returned sub-arrays
a = array1.slice(1)# 2nd element
b = array2.slice(2,3)# from 3rd element, return 3
c = array3.slice(1,1)# from 2nd element, return only 1
d = array4.slice(0,5)# from 1st element, return all elements
e = array5.slice(2)# return 3rd element# print returned values
puts "#{a}"# 2
puts "#{b}"# ["c", "d", "e"]
puts "#{c}"# ["dog"]
puts "#{d}"# [true, false, nil]
puts "#{e}"# false

each_slice và each_cons

  • each_slice :
(1..10).each_slice(3){|arr| p arr }# [1, 2, 3]# [4, 5, 6]# [7, 8, 9]# [10]
  • each_cons :
(1..10).each_cons(3){|arr| p arr }# [1, 2, 3]# [2, 3, 4]# [3, 4, 5]# [4, 5, 6]# [5, 6, 7]# [6, 7, 8]# [7, 8, 9]# [8, 9, 10]

push, pop, shift và unshift

  • push Thêm 1 phần tử vào cuối mảng
s =["one","two","three"]
s.push "four"# ["one", "two", "three", "four"]
  • pop Xóa phần tử cuối mảng
s =["one","two","three"]
s.pop

# ["one", "two"]
  • shift Xóa phần tử đầu mảng
s =["one","two","three"]
s.shift

# ["two", "three"]
  • unshift Thêm phần tử nil vào đầu mảng
s =["one","two","three"]
s.unshift

# [nil, "one", "two", "three"]

flatten, flatten! và reverse

  • flatten: Chuyển đổi cấu trúc của mảng từ mảng nhiều chiều thành mảng 1 chiều
[["apple"],["banana"],["orange"]].flatten #=> ["apple", "banana", "orange"]
  • flatten!: cũng là flatten nhưng nó không chỉ khác trên ở dấu !. Nếu mảng bị flatten là 1 chiều thì trả về nil
[["apple"],["banana"],["orange"]].flatten!#=> ["apple", "banana", "orange"]["apple","banana","orange"].flatten!#=> nil
  • reverse: Đảo chiều mảng đã cho
["apple","banana","orange"].reverse #=> ["orange", "banana", "apple"]

product và zip

  • product: trả về mảng chứa tổ hợp của phần tử của các mảng thành phần
[1,2].product([3,4])#=> [[1,3],[1,4],[2,3],[2,4]]
  • zip: trả về mảng tuyến tính từng phần tử
[1,2].zip([3,4])#=> [[1, 3], [2, 4]]

tranpose

Đại loại thì nó như sau

[[1,3],[1,4],[2,3],[2,4]].transpose

#=> [[1, 1, 2, 2], [3, 4, 3, 4]]

Hash

Hash là 1 cấu trúc cho phép map từng key với từng giá trị

Ví dụ:

h ={:foo=>0,:bar=>1,:baz=>2}
h # => {:foo=>0, :bar=>1, :baz=>2}

Chúng ta có thể chơi cú pháp kiểu JSON:

h ={foo:0, bar:1, baz:2}
h # => {:foo=>0, :bar=>1, :baz=>2}

Hoặc dùng chuỗi:

h ={'foo':0,'bar':1,'baz':2}
h # => {:foo=>0, :bar=>1, :baz=>2}

Xào nấu thập cẩm:

h ={foo:0,:bar=>1,'baz':2}
h # => {:foo=>0, :bar=>1, :baz=>2}

invert

invert là method cho phép hoán đổi key và value

h ={a:100, b:200}
puts h.invert #=> {100=>:a, 200=>:b}

Nếu trước khi invert 2 key có cùng value thì sau khi invert, giá trị sau cùng sẽ được lấy

h ={a:100, b:100}
puts h.invert #=> {100=>:b}

each

Dùng method each với Hash sẽ trả ra kiểu Array

h ={a:100}
h.each{|p|
  p p.class}# => Arry

Chú ý

hash ={klass =>100}

tương đương

hash ={}
hash.store(klass,100)

tương đương

hash =Hash[klass,100]

Chuỗi

%|apple banana orange|#=> "apple banana orange"

split

Chia 1 chuỗi ra thành các chuỗi con dựa theo kí tự phân tách. Trả về 1 mảng chứa các chuỗi con. Mặc định của ký tự phân tách là ' '

p "Apple Banana Lemon".split #=> ["Apple", "Banana", "Lemon"]
p "Apple Banana Lemon".split ' '#=> ["Apple", "Banana", "Lemon"]
p "Apple Banana Lemon".split / /#=> ["Apple", "Banana", "Lemon"]
p "Apple Banana Lemon".split /( )/#=> ["Apple", " ", "Banana", " ", "Lemon"]

Hãy lưu ý dấu ngoặc đơn.

strip!, chomp! và chop!

  • strip: xoá hết các kí tự trắng được định nghĩa trong Ruby trnfv
str ="Liberty Fish   rn"
str.strip!#=> "Liberty Fish"
  • chomp!: xoá đi kí tự hết dòng
str ="Liberty Fish   rn"
str.chomp!#=> "Liberty Fish   "
  • chop!: xoá kí tự cuối của chuỗi. Nhưng nếu là "rn" thì xoá cả 2
str ="Liberty Fish   rn"
str.chop!#=> "Liberty Fish   "
str ="Liberty Fish   rn"
str.chop!#=> "Liberty Fis"

Heredoc

Kết quả trả về của 1 chuỗi nhiều dòng sẽ chỉ tới ký tự Heredoc là hết

data =<<EOF
Hello,
World
EOF"EOF"#=> "Hello,nWorldn"

Time

Chủ yếu phần này sẽ hay hỏi ở strftime

Time + số

Các dạng Time + 1 số nào đó thì sẽ đều là chỉ số giây

strftime

Ký hiệu Ý nghĩa
%y Năm dạng tắt(ví dụ: 22)
%Y Năm dạng đủ(ví dụ: 2022)
%m Tháng(01-12)
%M Số phút(00-59)
%d Ngày(01-31)
%D, %x Ngày tháng năm dạng %m/%d/%y
%F %Y-%m-%d

Ví dụ:
Date.today.to_s tương đương với Date.today.strftime("%Y-%m-%d") và tương đương Date.today.strftime(%F)

File

dirname

dirname là method dùng để chỉ directory ngoài cùng của file

File.dirname("text.txt")# => "."File.dirname("REx/text.txt")# => "REx"File.dirname("Desktop/REx/text.txt")# => "Desktop/REx"

File.open và các param

Đây cũng là 1 phần quan trọng. Nếu nắm được và nhớ được thì có thể ghi điểm
Với code File.open('the_file_name.txt', XXXX) thì tuỳ từng param ở vị trí XXXX sẽ có những xử lý như sau

Param Ý nghĩa
'r' Chỉ đọc file
'r+' Đọc file và ghi đè
'w' Tạo mới và ghi đè(đọc sẽ báo lỗi not opened for reading (IOError))
'w+' Tạo mới, đọc và ghi đè
'a' Chỉ ghi thêm(đọc sẽ báo lỗi not opened for reading (IOError))
'a+' Đọc và ghi thêm

Dir

pwd

pwd trả về tên của client directory

Dir.pwd # => "/Users/user/RubyExamination"

Thread

Có 3 cách để tạo 1 Thread mới: Thread.new, Thread.startThread.fork

Biến

  • Hằng số trong Ruby bắt đầu bằng chữ cái alphabet viết in hoa: CONST1 = 129
  • Biến global trong Ruby bắt đầu bằng $: $var = "global"
  • Biến instance trong Ruby bắt đầu bằng @: @var = "instance"
  • Biến class trong Ruby bắt đầu bằng @@: @@var = "class". Phải được khởi tạo trước khi gọi trong method. Gọi 1 biến class chưa được định nghĩa sẽ xảy ra lỗi.

Class trong Ruby

Đây là phần chắc chắn là đau đầu trong tương lai nếu chúng ta thi chứng chỉ Ruby Gold. Ở mức Silver mới dừng ở những khái niệm cơ bản Module, Class thôi =)))

Cách định nghĩa Class và Module

Well, phần rất đơn giản thật =)) nhưng khi bạn có trộn thêm tí JS, Python để làm serverless trên AWS và thi thoảng phải động vào C# hay Java thì bạn đúng nghĩa là 1 Trại tâm thần đa ngôn ngữ…. lập trình :3 Nên cứ memo vào cho nó chắc để đỡ mất điểm oan

Định nghĩa module:

moduleMyModule...end

Định nghĩa class:

classMyClass...end

attr_accessor, attr_writer & attr_reader

attr_accessor:

classFoo
  attr_accessor :aend

tương đương với

classFoo# getterdefa@aend# setterdefa=(val)@a= val
  endend

Ta có thể gọi nhanh

foo =Foo.new
foo.a, foo.b ="aaa","bbb"

puts foo.a # => aaa
puts foo.b # => bbb

attr_reader:

classFoo
  attr_reader :adefinitialize@a="REx"endend

tương đương với

classFoo# getterdefa@aenddefinitialize@a="REx"endend

khi đó

foo =Foo.new
puts foo.a #=> 'REx'

attr_writer:

classFoo
  attr_writer :aend

tương đương với

classFoo# setterdefa=(val)@a= val
  endend

Exception

beginraiserescue=> e
  puts e.classend

Mặc định đoạn code này trả về RuntimeError.
Tuy nhiên, nếu sau raise thiết lập error khác thì e.class sẽ là error thiết lập

beginraiseArgumentErrorrescue=> e
  puts e.class# => ArgumentErrorend

Quay lại bài toán ban đầu

c =false||true?true&&false? a | b : a & b : b ;

có thể phân tích rõ thành c = (false || true) ? ((true && false) ? (a | b) : (a & b)) : b ;

Với false || true luôn trả kết quả true nên c = (true && false) ? (a | b) : (a & b)

false && true cũng trả kết quả true nên c = a | b

Vì vậy, với

a =[1,2,3,5,8]
b =[1,3,6,7,8]

thì c = a | b[1, 3, 8]

Một số bài tập khác

Bài tập 1

hoge =0defhoge
  x =05.times do|i|
    x +=1end
  x
end
puts hoge #=> 0

Lý do: Biến số sẽ được ưu tiên trước method

Bài tập 2

classFoo@@var=0defvar@@varenddefvar=(value)@@var= value
  endendclassBar<Fooend

foo =Foo.new
foo.var +=1
bar =Bar.new
bar.var +=2

puts "#{foo.var}/#{bar.var}"

Kết quả sẽ trả về 3/3 do khi viết như trên, foo.var == bar.var

Kết bài

Việc memo thế này thực ra từ kiến thức Ruby và phải nói thật là học tủ vì các method của Ruby rất nhiều và cực khó nhớ. Đây là cái do mình đọc sách, làm đề và viết lại để ghi nhớ. Rất mong các bạn có phần nào tham khảo được

Nguồn: viblo.asia

Bài viết liên quan

Thay đổi Package Name của Android Studio dể dàng với plugin APR

Nếu bạn đang gặp khó khăn hoặc bế tắc trong việc thay đổi package name trong And

Lỗi không Update Meta_Value Khi thay thế hình ảnh cũ bằng hình ảnh mới trong WordPress

Mã dưới đây hoạt động tốt có 1 lỗi không update được postmeta ” meta_key=

Bài 1 – React Native DevOps các khái niệm và các cài đặt căn bản

Hướng dẫn setup jenkins agent để bắt đầu build mobile bằng jenkins cho devloper an t

Chuyển đổi từ monolith sang microservices qua ví dụ

1. Why microservices? Microservices là kiến trúc hệ thống phần mềm hướng dịch vụ,