หา Ruby tricks ที่เก๋ๆ? เจอแล้ว! ในบทความนี้จะแชร์โปรดของผม
สารบัญ
- 1 Deep copy
- 2 วิธีต่างๆ เรียก lambda
- 3 สร้าง pre-filled array
- 4 True, false และ nil เป็น objects
- 5 Lambdas strict เรื่อง arguments แต่ Procs ไม่สนใจ
- 6 รันโค้ดโดยตรงโดยไม่ต้อง irb หรือไฟล์
- 7 Mini-irb ของตัวเองในคำสั่งเดียว
- 8 Unfreeze object (อันตราย!)
- 9 Objects ที่มี special identity
- 10 หลีกเลี่ยง big output ใน irb หรือ pry
- 11 ใช้ caller method ดึง call stack ปัจจุบัน
- 12 Bonus! แปลงค่าใดๆ เป็น boolean
- 13 Bonus! ใช้ Keyword เป็น Variable Name
- 14 สรุป
- 14.1 Related
Deep copy
ตอน copy object ที่มี object อื่นอยู่ภายใน เช่น Array จะ copy แค่ reference ของ object เหล่านั้น
เห็นได้ที่นี่:
food = %w( bread milk orange ) food.map(&:object_id) # [35401044, 35401020, 35400996] food.clone.map(&:object_id) # [35401044, 35401020, 35400996]
ใช้ class Marshal (ปกติใช้ serialization) สร้าง 'deep copy' ได้:
def deep_copy(obj) Marshal.load(Marshal.dump(obj)) end
ผลลัพธ์:
deep_copy(food).map(&:object_id) # [42975648, 42975624, 42975612]
วิธีต่างๆ เรียก lambda
my_lambda = -> { puts 'Hello' }
my_lambda.call
my_lambda[]
my_lambda.()
my_lambda.===
ถ้าเป็นไปได้ควรใช้ตัวแรก (call) เพราะคนส่วนใหญ่รู้จัก
สร้าง pre-filled array
Array class รับ argument + block ให้สร้าง array n elements ค่า default เป็น nil แต่ถ้ามี block ค่าจะมาจาก block
ตัวอย่าง:
Array.new(10) { rand 300 }
สร้าง array 10 ตัวเลขสุ่มระหว่าง 0-299
True, false และ nil เป็น objects
true.class # TrueClass false.class # FalseClass nil.class # NilClass
มีเพียงหนึ่ง copy ของ objects เหล่านี้ สร้างเพิ่มไม่ได้แม้จะอยาก นี่คือ singleton pattern ในการทำงาน
Lambdas strict เรื่อง arguments แต่ Procs ไม่สนใจ
my_lambda = ->(a, b) { a + b }
my_proc = Proc.new { |a, b| a + b }
my_lambda.call(2) # ArgumentError: wrong number of arguments (1 for 2)
my_proc.call(2) # TypeError: nil can't be coerced into Fixnum
รันโค้ดโดยตรงโดยไม่ต้อง irb หรือไฟล์
คำสั่ง ruby มี options น่าสนใจ เช่น flag -e ส่ง code snippet ให้ execute
ruby -e '5.times { puts "Fun with Ruby" }'
หาเพิ่มได้ด้วย flag -h
Mini-irb ของตัวเองในคำสั่งเดียว
เคยอยากรู้ irq ทำงานอย่างไร? นี่คือ super-simple version จำว่า 'REPL' ย่อมาจาก: Read-Eval-Print Loop
ruby -n -e 'p eval($_)'
ไม่ได้ prompt แต่ไป ahead พิมพ์ Ruby code ได้
"A" * 5 "AAAAA"
ทำงานเพราะ flag -n ทำอย่างนี้:
-n assume 'while gets(); ... end' loop around your script
และ $_ เป็น global variable มีค่า:
The last input line of string by gets or readline.
Unfreeze object (อันตราย!)
ไม่มี Ruby method unfreeze object แต่用 Fiddle class เข้า Ruby internals ทำได้
require 'fiddle' str = 'water'.freeze str.frozen? # true memory_address = str.object_id * 2 Fiddle::Pointer.new(memory_address)[1] &= ~8 str.frozen? # false
อย่าลองที่บ้าน!
Objects ที่มี special identity
Ruby objects มี identifier หรือ 'id' number เข้าถึงได้ด้วย object_id บาง objects มี fixed id: Fixnums, true, false, nil
false.object_id # 0 true.object_id # 2 nil.object_id # 4 1.object_id # 3 2.object_id # 5
Fixnum ids ใช้สูตร: (number * 2) + 1 Bonus: Fixnum สูงสุดคือ 1073741823 หลังนั้นได้ Bignum object
หลีกเลี่ยง big output ใน irb หรือ pry
ถ้าทำงานใน irb อยากหลีกเลี่ยงเติมหน้าจอด้วย huge array หรือ string ให้ append ; ท้ายโค้ด
ตัวอย่าง:
require 'rest-client'
RestClient.get('www.rubyguides.com');
ลองอีกครั้งไม่มี ; ดูความต่าง 🙂
ใช้ caller method ดึง current call stack
ตัวอย่างโค้ด:
def foo bar end def bar puts caller end foo
Output:
-:3:in 'foo' -:10:in '<main>'
ถ้าต้องการ current method name ใช้ __method__ หรือ __callee__
Bonus! แปลงค่าใดๆ เป็น boolean
!!(1) # true !!(nil) # false
Bonus! ใช้ Keyword เป็น Variable Name
def foo (if: nil) binding.local_variable_get(:if) end foo(if: true)
สรุป
หวังว่าจะชอบ Ruby tricks นี้! แชร์ให้เพื่อนๆ และ สมัครรับ blog ในฟอร์มด้านล่างเพื่อไม่พลาดโพสต์ถัดไป 🙂