คุณกำลังมองหาวัตถุที่มีลักษณะเหมือน IO วัตถุ (ไฟล์ ซ็อกเก็ต ฯลฯ) แต่คุณสามารถควบคุมได้เหมือนสตริงหรือไม่
แล้วก็ StringIO สำหรับคุณ
ผมขอแสดงตัวอย่างและสิ่งที่ควรระวัง!
ตัวอย่างพื้นฐาน
การสร้าง StringIO วัตถุที่คุณสามารถทำได้:
io = StringIO.new("abc")
จากนั้นคุณสามารถอ่านจากวัตถุนี้โดยใช้วิธีการเช่น gets , read &each_line .
ฉันทำตารางที่มีประโยชน์สำหรับคุณด้วยวิธีที่มีประโยชน์ที่สุด:
| วิธีการ | คำอธิบาย |
|---|---|
| ได้รับ | อ่านอินพุตหนึ่งบรรทัด |
| อ่าน | อ่านจำนวนไบต์ที่ระบุ (ทั้งหมดเป็นค่าเริ่มต้น) |
| each_line | กำหนดบล็อก วนซ้ำในแต่ละบรรทัด |
| each_char | กำหนดบล็อก วนซ้ำอักขระแต่ละตัว |
| << | ผนวกข้อมูล |
| กรอกลับ | รีเซ็ตตัวชี้ตำแหน่งภายใน |
| สตริง | คืนค่าสตริงจริงจากออบเจ็กต์ stringio |
ขอให้สังเกตว่า StringIO มีตัวชี้ตำแหน่ง
ตัวชี้นี้จะติดตามจำนวนไบต์ที่คุณอ่าน เช่นเดียวกับวัตถุไฟล์
ดังนั้นทุกครั้งที่คุณเรียกใช้เมธอดอย่าง gets หรือ read มันจะให้ข้อมูลจำนวนนั้นแก่คุณ &เลื่อนตัวชี้
แม้แต่วิธีการนับได้เช่น map หรือ each_line จะเลื่อนตัวชี้ตำแหน่ง ดังนั้นโปรดระลึกไว้เสมอว่า
io.each_line { |line| puts line }
คุณสามารถรีเซ็ตตัวชี้ตำแหน่งไปที่จุดเริ่มต้นโดยใช้ rewind วิธีการ:
io.pos # 45 io.rewind io.pos # 0
เท่านั้นสำหรับพื้นฐาน
ฉันจะแสดงให้คุณเห็นการใช้งานจริงบางประการสำหรับ StringIO แต่ก่อนอื่น ให้ฉันแสดงอย่างอื่นให้คุณดูก่อน
แล้วอะไรเกี่ยวกับ StringScanner
ตอนนี้คุณได้เห็นแล้วว่า StringIO ทำได้ แต่ Ruby Standard Library มีคลาสอื่นที่เกี่ยวข้องกับสตริง
คลาสนั้นคือ StringScanner
อาจทำให้สับสนได้เนื่องจากมีชื่อและวิธีการคล้ายกัน แต่ให้ฉันช่วยคุณเห็นความแตกต่าง
สิ่งสำคัญคือสิ่งนี้ :
StringIO วัตถุสามารถแทนที่ IO . อื่นได้ วัตถุ (เช่น File หรือ Socket ) แต่ StringScanner มีไว้สำหรับทำสิ่งต่าง ๆ เช่นการแยกวิเคราะห์ (ทำให้ข้อความบางส่วนมีความหมายโดยแบ่งเป็นชุดโทเค็น)
คลาสทั้งสองนี้ยังคงแบ่งปันบางสิ่ง นอกเหนือจากการมี “สตริง” ในชื่อ พวกเขาทั้งคู่ใช้ตัวชี้ตำแหน่งภายใน .
การแทนที่อินพุตและเอาต์พุตมาตรฐาน
สมมติว่าคุณกำลังเขียนแอปพลิเคชันบรรทัดคำสั่งที่ขอผลลัพธ์จากผู้ใช้โดยใช้วิธี Kernel#gets…
…ถ้าคุณต้องการทดสอบโค้ดนี้ คุณจะต้องป้อนข้อมูลบางอย่างด้วยมือทุกครั้ง
เป็นการทดสอบอัตโนมัติจากภาพหรือไม่
ไม่ มันไม่ใช่!
นี่คือที่ที่ StringIO มาเพื่อช่วยชีวิต คุณสามารถเริ่มต้น StringIO วัตถุด้วยอินพุตทดสอบของคุณแล้วแทนที่วัตถุอินพุตมาตรฐานที่ชี้ด้วย $stdin (นี่คือที่ที่ Ruby ค้นหาอินพุตของผู้ใช้เมื่อคุณเรียก gets )
ตัวอย่าง :
io = StringIO.new("input")
$stdin = io
gets
# input
เทคนิคนี้ยังสามารถใช้เพื่อจับภาพผลลัพธ์จากวิธีการต่างๆ เช่น puts .
วิธีการแสดงผลจะพิมพ์ไปยังอุปกรณ์ส่งออกเริ่มต้นที่เรียกว่า 'เอาต์พุตมาตรฐาน' ใน Ruby แสดงด้วย IO วัตถุที่คุณสามารถแทนที่ด้วย StringIO . ของคุณ วัตถุ
ตัวอย่าง :
io = StringIO.new("")
$stdout = io
# Print to $stdout
puts "Jesus Castello is from Spain & likes to help people learn Ruby."
# Restore original value
$stdout = STDOUT
io.rewind
io.read
# "Jesus Castello is from Spain & likes to help people learn Ruby."
สิ่งนี้มีความเกี่ยวข้องมากกว่าเวอร์ชันอินพุต เนื่องจากเราต้องการให้แน่ใจว่าได้กู้คืน STDOUT ดั้งเดิม วัตถุ &เพื่อย้อนกลับ StringIO . ของเรา เพื่อให้เราสามารถอ่านผลลัพธ์ได้
สังเกตว่าเฟรมเวิร์กการทดสอบส่วนใหญ่มีวิธีการทำเช่นนี้ให้คุณ (asssert_output สำหรับ Minitest &ตัวจับคู่เอาต์พุตใน RSpec) แต่การรู้ว่าเกิดอะไรขึ้นเบื้องหลังนั้นเป็นเรื่องที่ดีเสมอ 🙂
สรุป
คุณได้เรียนรู้เกี่ยวกับ StringIO คลาสซึ่งเลียนแบบ IO . ของจริง วัตถุจึงทำหน้าที่แทนวัตถุชนิดนั้นได้
ซึ่งจะเป็นประโยชน์สำหรับการทดสอบคลาสที่เขียนเอาต์พุตไปยังหน้าจอหรือกำหนดให้ผู้ใช้ป้อนข้อมูลผ่านเทอร์มินัล
หากคุณรู้จักการใช้ StringIO . ที่น่าสนใจ แจ้งให้เราทราบในความคิดเห็นและอย่าลืม แชร์สิ่งนี้ บทความเพื่อให้ผู้คนได้เพลิดเพลินมากขึ้น!