Ruby เป็นภาษาที่ยอดเยี่ยม สร้างขึ้นเพื่อมนุษย์มาก่อนและรองจากเครื่องจักร มันง่ายต่อการอ่านและเขียน มีหลายวิธีในการเขียนอะไรก็ได้ และคุณมักจะเดาไลบรารี่มาตรฐานได้โดยการพิมพ์ชื่อธีมที่คุณจะเลือกเอง
ด้วยเหตุนี้ ข้อโต้แย้งของ Ruby จึงมีความยืดหยุ่นมาก ซึ่งทำให้เราสามารถแสดง API ของเราได้อย่างชัดเจน แต่สิ่งนี้มาพร้อมกับข้อเสียเปรียบ:Ruby นั้นค่อนข้างยากที่จะแยกวิเคราะห์สำหรับนักพัฒนา Cextension!
ในบทความนี้ เราจะอธิบายสองวิธีในการตั้งค่า Ruby API ที่ซับซ้อนซึ่งเขียนด้วยภาษา C:
- ด้วย
03และแยกวิเคราะห์ด้วย19 - การใช้อินเทอร์เฟซ Ruby
มาเริ่มกันเลย!
C และ Ruby:บทนำ
ตามที่กล่าวไว้ Ruby นั้นแยกวิเคราะห์ได้ยากสำหรับนักพัฒนาส่วนขยาย C
ตัวอย่างเช่น:
ความงดงามของภาษา C ซึ่งเป็นภาษา Ruby ที่เขียนขึ้นนั้น มีต้นกำเนิดมาจากความเรียบง่าย รวมถึงในพารามิเตอร์ฟังก์ชันด้วย:
23รหัส>30รหัส> สำหรับการโต้แย้งที่หลากหลาย
สิ่งเหล่านี้จะช่วยคุณรักษาฐานโค้ดที่เข้าใจได้ไม่ยาก
นี่เป็นวิธีที่ซับซ้อนที่สุดในการกำหนดฟังก์ชัน C:
เมื่อคุณเขียนโค้ดส่วนขยาย C สำหรับโค้ดเบส Ruby คุณจะเริ่มเข้าใจว่าความซับซ้อนเริ่มต้นที่ใด แต่ไม่ต้องกังวล — นักพัฒนา Ruby MRI ให้เราครอบคลุมแล้ว
คำจำกัดความวิธีการอย่างง่ายในส่วนขยาย Ruby C
เราจะเริ่มต้นด้วยวิธีการที่คุณจะต้องใช้ ณ จุดใดจุดหนึ่ง 41 .
คุณยังสามารถปฏิบัติตามตัวอย่างโค้ดใน repo นี้ได้อีกด้วย
นี่คือ 56 ลายเซ็นต์:
และตาม extension.rdoc ของ Ruby:
argc คือจำนวนอาร์กิวเมนต์ ถ้า argc เป็น -1 ฟังก์ชันจะได้รับ 3 อาร์กิวเมนต์:argc, argv และ self ถ้า argc เป็น -2 ฟังก์ชันจะรับ 2 อาร์กิวเมนต์ คือ self และ args โดยที่ args คืออาร์เรย์ Ruby ของอาร์กิวเมนต์ของเมธอด
โดยสรุป:
ดังนั้น หาก API ของคุณประกอบด้วยเมธอดที่มีความยาวพารามิเตอร์คงที่ หรือมีพารามิเตอร์แปรผันเพียงตัวเดียว (64 ) ไม่ต้องอ่านต่อ — คุณทำเสร็จแล้ว! หากคุณต้องการวิธีการเรียก API ของคุณที่สมบูรณ์ยิ่งขึ้น โปรดมาเป็นแขกของฉัน
อย่างไรก็ตาม หากคุณต้องการตัวอย่างที่เกี่ยวข้องเพิ่มเติมใน 73 ขอแนะนำให้คุณอ่านบทความของ Peter Zhu เกี่ยวกับ Dinning Methods ป>
การใช้ Ruby C API ภายใน
กลับไปที่กรณีการใช้งานของเรา:แยกวิเคราะห์ข้อโต้แย้งที่ซับซ้อน โชคดีที่เครื่องมือบางอย่างสามารถช่วยเราได้
แต่ก่อนอื่น เรามาดูข้อจำกัดของการใช้ 82 เพียงอย่างเดียว .
ข้อเสียของ 95
ไม่มีการกล่าวถึงข้อโต้แย้งที่ถูกบล็อก
ข้อจำกัดประการหนึ่งคือ 105 ไม่เคยกล่าวถึงข้อโต้แย้งแบบบล็อก สิ่งเหล่านั้นไม่ได้รับการพิจารณาเพราะมันไม่สำคัญสำหรับ Ruby อยู่แล้วหากคุณผ่านบล็อก คุณยังคงสามารถมั่นใจได้ว่าบล็อกถูกส่งผ่านโดยใช้119 หรือ 123รหัส> . มีข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อนั้นในบทความของ Peter Zhu
อาร์กิวเมนต์อาจแตกต่างกันไป
ข้อจำกัดที่สำคัญอีกประการหนึ่งคือ args อาจแตกต่างกันไป แต่ตัววิธีการเรียกนั้นไม่ได้ถูกจำกัดมากนัก ดังนั้น หากคุณต้องการให้ API ของคุณเป็น 138 คุณจะต้องแยกวิเคราะห์ข้อโต้แย้งของคุณ มีหลายวิธีที่จะช่วยคุณในเส้นทางนั้น 149รหัส> เป็นเวอร์ชันที่คุณสามารถใช้ได้พร้อมกับเวอร์ชัน -1 ของ 158 .
นี่คือลายเซ็นของฟังก์ชัน:
ข้อโต้แย้งของคำหลัก
ข้อจำกัดสุดท้ายประการหนึ่งที่เราจะพูดถึงคือการใช้อาร์กิวเมนต์ของคำหลัก และฉันเก็บสิ่งที่ดีที่สุดไว้เป็นลำดับสุดท้าย เนื่องจากนั่นจะเป็นหัวใจสำคัญของบทความนี้
เราต้องดึงข้อโต้แย้งของคำหลักก่อนจึงจะสามารถแยกวิเคราะห์ได้อย่างถูกต้อง โชคดีที่ Ruby C API มาพร้อมกับวิธีการนี้161 .
นี่คือ 171 ลายเซ็นต์:
คุณผ่าน 184 198รหัส> และ 209รหัส> มอบให้โดย 210 — สตริงที่ระบุว่าควรแยกอาร์กิวเมนต์อย่างไร (222 ) และผู้รับข้อโต้แย้งเหล่านั้น เอาล่ะ ความซับซ้อน args ทั้งหมดของ Ruby ถูกแยกวิเคราะห์ในบรรทัดเดียว! เกือบแล้ว
คุณสามารถอ้างอิงถึง extension.rdoc เพื่อเป็นตัวแทนอย่างเป็นทางการว่า 231 ควรเขียนไว้ แม้ว่าเราจะกล่าวถึงบางส่วนในตัวอย่างด้านล่างก็ตาม
เขียนและแยกวิเคราะห์ฟังก์ชัน:ตัวอย่าง
สำหรับส่วนที่เหลือของบทความนี้ ลองพิจารณาว่าเราต้องการเขียนฟังก์ชันนี้:
แยกวิเคราะห์โดยใช้ 247 จะมีลักษณะดังนี้:
250รหัส> พูดพล่อยๆ หมายถึง:
264รหัส> :อาร์กิวเมนต์ตำแหน่งที่ต้องการหนึ่งรายการ277รหัส> :ไม่จำเป็นต้องใช้ข้อโต้แย้งเกี่ยวกับตำแหน่งจำนวนเท่าใดก็ได้281รหัส> :อาร์กิวเมนต์คำหลักในตอนท้าย
แยกวิเคราะห์อาร์กิวเมนต์คำหลัก
ตอนนี้เราได้จำกัดวิธีการไว้แล้ว แต่น่าเสียดายที่เรายังดำเนินการไม่เสร็จ API ปัจจุบันของเราคือ 290 .
ท้ายที่สุด เราจำเป็นต้องแยกวิเคราะห์ข้อโต้แย้งของคำหลักเหล่านั้นโดยใช้ 308 .
คุณต้องเลือกอาร์กิวเมนต์ที่จำเป็นและเป็นทางเลือก เมื่อเสร็จแล้ว ให้ใช้ 314 เพื่อบอก Ruby ถึงชื่อของอาร์กิวเมนต์เหล่านั้น และคุณเก็บผลลัพธ์ไว้ในอาร์เรย์ (326 ).
ได้แล้ว! วิธี Ruby ที่ซับซ้อน แยกวิเคราะห์โดยใช้ C เท่านั้น อย่างไรก็ตาม หากวิธีนี้ซับซ้อนเกินไปสำหรับคุณ ก็มีตัวเลือกอื่น
การใช้อินเทอร์เฟซ Ruby
อีกวิธีหนึ่งในการจัดการปัญหาคือการใช้ไวยากรณ์ของ Ruby โดยตรงและทำการแยกวิเคราะห์ที่ระยะ Ruby
ด้วยวิธีนี้ คุณสามารถใช้รูปแบบที่สามของ 336 ได้โดยตรง สำหรับวิธี C ที่มีลักษณะดังนี้:
และไปได้แล้ว — คุณหลีกเลี่ยงปัญหาได้อย่างสมบูรณ์ด้วยโซลูชันที่หรูหราซึ่งจริง ๆ แล้วใช้สำหรับวิธีการบางอย่างในการใช้งาน Rubyimplementation (ด้วย 346 คลาส).
แม้ว่าคลาสที่ใช้โดย MRI จะค่อนข้างซับซ้อนและสร้าง C ขึ้นมาเอง แต่เราก็สามารถได้รับแรงบันดาลใจจากมันได้
มาสร้างวัตถุและเสียบวิธีการของเราเพื่อหลีกเลี่ยงการมองเห็น 357 สำหรับผู้ใช้ API ของเรา:
ลองดูกรณีการใช้งานจริงของคลาสนี้ในโค้ดเบสของ RGeo
การแยกวิเคราะห์อาร์กิวเมนต์:ฉันควรใช้วิธีใด
Repo นี้แสดงสองวิธีในการตั้งค่า Ruby API ที่ซับซ้อนซึ่งเขียนด้วยภาษา C — เพื่อสรุป:
- ด้วย
364และแยกวิเคราะห์ด้วย372 - การใช้อินเทอร์เฟซ Ruby
เมื่อเราเปรียบเทียบโซลูชันทั้งสองในแง่ของประสิทธิภาพ จะใกล้เคียงกันโดยประมาณ (การแยกวิเคราะห์ Ruby เร็วกว่าโดยเฉลี่ย 1.02 เท่าใน M1 ของฉัน) นั่นไม่ได้สร้างความแตกต่างมากนัก
ใน RGeo lib ตัวเลือกการออกแบบแรกของเราคือการมี API ที่ใช้อาร์กิวเมนต์ความยาวแปรผันเท่านั้น ไม่มีคำหลัก ไม่มีการบล็อก สิ่งนี้อาจเป็นการจำกัด และตอนนี้เรากำลังใช้ 384 วิธีที่จะยอมให้มีข้อโต้แย้งที่ซับซ้อนมากขึ้น
ประโยชน์ของการใช้อินเทอร์เฟซ Ruby
คำแนะนำของฉันคือการใช้อินเทอร์เฟซ Ruby ด้วยเหตุผลหลายประการ รวมถึง:
- ขนาดโค้ดเล็กลง
- การเปลี่ยนแปลงทำได้ง่ายขึ้น
โดยรวมแล้ว สิ่งนี้ทำให้ประสบการณ์การอ่านโค้ดเบสของคุณง่ายขึ้น
การดึงดูดผู้ใช้ Ruby ให้อ่านซอร์สโค้ดของ gems ที่พวกเขาใช้นั้นสำคัญสำหรับฉัน เนื่องจาก Ruby อ่านง่าย อัญมณีก็ควรจะเป็นเช่นนั้นเช่นกัน
ประโยชน์ของการใช้ 390
อย่างไรก็ตาม เวอร์ชัน C ช่วยให้เราได้สัมผัสถึงวิธีการภายในที่มีประโยชน์มากบางอย่าง เช่น 402 ยังคงมีประโยชน์จริงๆ วิธีการจัดการบล็อคก็ทำได้ดีเช่นกัน และคุณอาจไม่จำเป็นต้องใช้ forblock ด้านหน้าของ Ruby
มันคือทั้งหมดที่เกี่ยวกับการค้นหาตัวเลือกที่ดีที่สุดสำหรับกรณีการใช้งานของคุณ
สรุป
ในโพสต์นี้ เราได้สำรวจสองวิธีในการแยกวิเคราะห์อาร์กิวเมนต์ในส่วนขยาย Ruby C ของคุณ — โดยใช้ 412 (ดูข้อ จำกัด ของมันโดยสังเขปด้วย) และแยกวิเคราะห์ด้วย 425 และใช้อินเทอร์เฟซ Ruby
หากคุณต้องการอ่านเพิ่มเติมเกี่ยวกับส่วนขยาย C ฉันขอแนะนำ:
- การสร้างส่วนขยาย Ruby C ตั้งแต่เริ่มต้น
- นักทับทิมเดินเลียบฝั่ง C
- การทำงานกับส่วนขยาย Ruby C บน Mac
และคำแนะนำสุดท้ายของฉันสำหรับคุณ:ลองดู RGeo เป็นโค้ดเบสส่วนขยาย C ที่ใช้กันอย่างแพร่หลายในการพัฒนาอย่างแข็งขัน ตัวอย่างของฉันส่วนใหญ่มาจากที่นี่
ขอให้สนุกกับการเขียนโค้ด!
ปล. หากคุณต้องการอ่านโพสต์ Ruby Magic ทันทีที่เผยแพร่ สมัครรับจดหมายข่าว Ruby Magic ของเราและไม่พลาดแม้แต่โพสต์เดียว! ป>
ยูลิสซี บูโอโนโม
Ulysse ผู้เขียนรับเชิญของเราคืออดีตนักพัฒนา Ruby ในอุตสาหกรรมที่อุทิศเวลาส่วนใหญ่ให้กับการเดินทางรอบโลก เวลาว่างของเขาทุ่มเทให้กับ RGeo และ Ruby และเขาชอบที่จะปรับแต่งระบบภายในของ Ruby
บทความทั้งหมดโดย Ulysse Buonomo