Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

ค้นพบ 9 การปรับปรุงสำคัญใน Ruby 2.4: สิ่งที่นักพัฒนาต้องรู้

การปล่อย Ruby ใหม่ในวันคริสต์มาสกลายเป็นประเพณีแล้ว

ในบทความนี้ ผมอยากครอบคลุมการเปลี่ยนแปลงน่าสนใจใน Ruby 2.4 เพื่อให้คุณทันข่าวสาร 🙂

Float#round รองรับ keyword argument

ถ้าคุณใช้ float ในแอป ผมหวังว่าคุณใช้ floor หรือ ceil สำหรับการปัดเศษ เพราะพฤติกรรมเริ่มต้นของ Float#round เปลี่ยนไปใน Ruby 2.4

ตัวอย่าง:

# Ruby 2.3
(2.5).round # 3

# Ruby 2.4
(2.5).round # 2

พฤติกรรมเริ่มต้นตอนนี้คือ "round-to-nearest-even" (ปัดเป็นเลขคู่ที่ใกล้ที่สุด)

อัปเดต: พฤติกรรมเริ่มต้นของ Float#round กลับมาเป็น "ปัดขึ้น" ใน Ruby 2.4 เวอร์ชันสุดท้าย นี่คือการตัดสินใจของ Matz หลังจากบทความนี้เผยแพร่ไปแล้ว

เพิ่มเติม Float#round ตอนนี้รับอาร์กิวเมนต์ keyword เพื่อกำหนดประเภทการปัดเศษ:

  • :even
  • :up
  • :down

ตัวอย่าง:

(4.5).round(half: :up) # 5

นอกจากนี้ Float#floor, Float#ceil และ Float#truncate ตอนนี้รับ optional argument เพื่อกำหนดความแม่นยำ (precision)

Flag chomp สำหรับเมธอด IO

ถ้าคุณเคยใช้เมธอดอย่าง gets หรือ each_line คุณคงจำได้ว่าต้องจัดการกับตัวอักษรขึ้นบรรทัดใหม่ (\n) ที่รบกวน

นี่คือสิ่งที่มือใหม่มักมีปัญหา แต่ฟีเจอร์ใหม่นี้อาจช่วยได้!

ตัวอย่างเดิม:

input = gets.chomp # "abc\n"

ตอนนี้ใน Ruby 2.4 คุณสามารถตั้ง keyword argument chomp ให้ gets ตัดตัวอักษรขึ้นบรรทัดใหม่ให้อัตโนมัติ

ตัวอย่าง:

input = gets(chomp: true) # "abc"

ทำงานกับค่าใดๆ ที่ไม่ใช่ false หรือ nil (ค่า "falsy" เพียงสองอย่างใน Ruby)

ดังนั้นนี้ก็ทำงานได้ (แต่ไม่แนะนำเพราะสับสน):

input = gets(chomp: 1234) # "abc"

ไม่ได้เป็นเรื่องใหญ่ แต่ประหยัดการเรียกเมธอดหนึ่งครั้ง 🙂

Pathname#empty?

Ruby 2.4 เพิ่ม Dir#empty? และ File#empty? สำหรับตรวจสอบว่าไดเรกทอรีหรือไฟล์ว่างเปล่า

แต่ Pathname#empty? ก็ถูกเพิ่มเข้ามาเช่นกัน

กรณีที่คุณไม่คุ้นเคยกับ Pathname มันคือคลาสที่รวมฟังก์ชันของ Dir และ File ไว้ด้วยกัน

เพิ่มเติม มัน "OO" (Object Oriented) มากกว่า เพราะคืนค่าเป็นออบเจ็กต์ Pathname แทนที่จะเป็นสตริง

ตัวอย่าง:

Pathname.empty?("file or directory name")

Commit: https://github.com/ruby/ruby/commit/9373c5efb993dd8cae0526118805449b19af2c22

Set#compare_by_identity

Set เป็นโครงสร้างข้อมูลใน standard library ช่วยเก็บคอลเลกชันของไอเทมที่ไม่ซ้ำกัน

โดยค่าเริ่มต้น ออบเจ็กต์ถูกเปรียบเทียบจากค่า (หรือแม่นยำกว่าคือ hash value)

แต่ใน Ruby 2.4 สามารถมี Set ของออบเจ็กต์ที่ไม่ซ้ำกันตาม object id ได้

ตัวอย่าง:

require 'set'

# Set ปกติ
set = Set.new
set << 123 << 123 << "abc" << "abc"
# [123, "abc"]

# Identity set
set = Set.new.compare_by_identity
set << 123 << 123 << "abc" << "abc"
# [123, "abc", "abc"]

ถ้าใครรู้ use case น่าสนใจของฟีเจอร์นี้ ลองคอมเมนต์บอกกัน 🙂

Commit: https://github.com/ruby/ruby/commit/76977611dd68e384fdce8c546efda5e1931e67a6

Refinements รองรับ Kernel#send, BasicObject#__send__, Symbol#to_proc

ผมไม่ได้ลงลึกเรื่อง refinements ที่นี่ แต่อย่างง่ายคือการเพิ่มเมธอดให้คลาสอย่าง String พร้อมเก็บการเปลี่ยนแปลงไว้ "เฉพาะที่" (localized) ในไฟล์หรือคลาสเดียว

ตั้งแต่ Ruby 2.4 เมธอดที่กำหนดผ่าน refinements จะเข้าถึงได้เมื่อเรียกผ่าน Kernel#send และ Symbol#to_proc

ตัวอย่าง:

module TenTimes
  refine String do
    def ten_times
      puts self * 10
    end
  end
end

class Thing
  using TenTimes
  "abc".send(:ten_times)
end

ถ้าลองใน 2.3 หรือต่ำกว่า จะได้ error 'undefined method'

Commit: https://github.com/ruby/ruby/commit/35a29390197750abf97ef16fa0740e377764daef

Hash#transform_values

อีกเมธอดหนึ่งที่มาจาก Rails เข้าสู่ Ruby core คือ Hash#transform_values ทำงานคล้าย Array#map

ตัวอย่าง:

h = {a: 1, b: 2, c: 3}
h.transform_values { |v| v * 10 } # {a: 10, b: 20, c: 30}

ยังมี Hash#transform_values! สำหรับการ mutate แบบ in-place

Kernel#clone รับ keyword argument ทางเลือก

คุณรู้ไหมว่าสามารถ copy ออบเจ็กต์ Ruby ได้? มีประโยชน์เพราะออบเจ็กต์ส่วนใหญ่เป็น mutable และคุณอาจอยากหลีกเลี่ยงการเปลี่ยนแปลงออบเจ็กต์ต้นฉบับ

มีสองเมธอดสำหรับ copy:

  • clone
  • dup

มีความต่างเล็กน้อยระหว่าง clone และ dup แต่สรุปง่ายๆ คือ clone เก็บสถานะ "frozen" ของออบเจ็กต์ต้นฉบับ ส่วน dup ไม่เก็บ

ใหม่ใน 2.4 คือ เรียก clone พร้อม flag "freeze" ได้

ตัวอย่าง:

foo = "test".freeze
boo = foo.clone(freeze: false)
boo.frozen? # false

ไม่แน่ใจว่ามีประโยชน์มากแค่ไหน แต่มีตัวเลือกมากกว่าไม่ได้ทำอะไร 🙂

Commit: https://github.com/ruby/ruby/commit/320ae01c5fb091eab0926c186f304a9caeda1ace

Thread.report_on_exception

ฟีเจอร์ใหม่อีกอย่างคือ Thread.report_on_exception 提出มากเพราะข้อยกเว้นในเธรดเป็น silent โดยค่าเริ่มต้น ซึ่งอาจซ่อนปัญหาในโค้ดของคุณ

ค่าเริ่มต้นคือ false แต่ถ้าแอปของคุณใช้เธรด ควรลองเปิดใช้ตอนอัปเกรดเป็น Ruby 2.4

ตัวอย่าง:

Thread.report_on_exception = true

t1 = Thread.new do
  puts "In new thread"
  raise "Exception from thread"
end

sleep(1)
puts "In the main thread"

จะแสดงข้อยกเว้น แต่ไม่ทำให้โปรแกรม crash ตัวเลือกอีกอย่างคือ Thread.abort_on_exception ที่มีมาตลอด

สังเกตว่ามี instance version ด้วย จึงตั้งค่าได้ต่อเธรด ไม่ใช่ทั้งหมด

Binding#irb

คุณแฟนของ binding.pry สำหรับ debug ไหม? ตอนนี้มี binding.irb ที่ทำงานคล้ายกัน

แต่มันเป็น irb จึงไม่ได้ฟีเจอร์ดีๆ อย่าง syntax highlighting ของ pry

ดีกว่าไม่มีอะไรเลย ถ้าคุณไม่มี pry ใช้งาน 🙂

Commit: https://github.com/ruby/ruby/commit/493e48897421d176a8faf0f0820323d79ecdf94a

สรุป

Ruby เวอร์ชันใหม่นี้นำฟีเจอร์น่าสนใจหลายอย่างมา อย่าลืมลองดูตอนพร้อมใช้งาน

อย่าลืม แชร์บทความนี้ ให้เพื่อนๆ รู้จักฟีเจอร์ใหม่ใน Ruby 2.4!