ฉันจะใช้ nadvice ได้อย่างไร


29

การกำหนดค่าของฉันเต็มไปด้วยคำแนะนำและฉันยังคงได้ยินเกี่ยวกับnadvice.elแพคเกจminimalist minimalist ใหม่

ฉันค้นหาคู่มือและฉันอ่านแหล่งข้อมูลแล้ว แต่ฉันจะยอมรับอย่างเปิดเผย: ฉันยังไม่รู้ว่าจะใช้งานอย่างไร

ทุกคนที่นี่สามารถชี้แนะทางให้ฉันหรือบอกวิธีเริ่มใช้คำแนะนำแบบเก่าของฉันได้อย่างไร


7
+1 สำหรับคำถาม หากคุณได้ค้นหาคู่มือและไม่พบสิ่งที่คุณจำเป็นโปรดพิจารณาการยื่น (doc) M-x report-emacs-bugรายงานข้อผิดพลาด: นักพัฒนาบางคนชอบที่จะพัฒนามากกว่าการทำเอกสาร ;-) เป็นสิ่งสำคัญที่ Emacs จะต้องจัดทำเอกสารเอง
Drew

2
คู่มือการใช้งานจริงมีส่วนที่ให้ดู(ข้อมูล "(Elisp) แจงคำแนะนำเก่า") มันไม่ได้อยู่ในดัชนีรายละเอียดด้วยเหตุผลใดก็ตาม
wasamasa


3
ตัวอย่างบางส่วนที่ใช้nadviceจากการตั้งค่าของฉัน: : หลังจาก , กรองผลตอบแทน , : รอบ , ก่อนจนกว่า
Kaushal Modi

1
@wasamasa ฉันเกรงว่าส่วนนั้นยังไม่สมบูรณ์ ฉันมีคำแนะนำเล็กน้อย (อาจเป็นเพียงแค่เราจะเห็น) ที่ซับซ้อนมากขึ้น ฉันควรตั้งคำถามที่นี่หรือไม่?
PythonNut

คำตอบ:


22

ข้อมูลทั้งหมดที่คุณต้องการรวมอยู่ในซึ่งอธิบายกลไกพื้นฐานของC-h f add-functionadvice-add

ระบบคำแนะนำใหม่โดยทั่วไปจะทำหน้าที่แทนการนิยามคำจำกัดความปัจจุบันของฟังก์ชันด้วยฟังก์ชันที่อธิบายไว้ในตาราง C-h f add-functionโดยขึ้นอยู่กับการเลือกWHERE อาร์กิวเมนต์ที่คุณเลือกเท่านั้นที่สะอาดกว่าเพื่อติดตามพฤติกรรมที่กำหนดไว้ในไฟล์ต้นฉบับ

ตัวอย่างพร้อม:aroundตัวเลือก

กรณีทั่วไปมากที่สุดคือ:aroundตัวเลือกดังนั้นฉันให้ตัวอย่างสำหรับสิ่งนั้น (น่าจะดีกว่าถ้าใช้WHEREพารามิเตอร์เฉพาะเมื่อเป็นไปได้ แต่คุณสามารถแทนที่กันด้วย:aroundฟังก์ชันที่เทียบเท่า )

ตัวอย่างเช่นสมมติว่าคุณต้องการดีบักการใช้งานบางอย่างfind-file และต้องการprintรายการอาร์กิวเมนต์ทุกครั้งที่มีการเรียกใช้ คุณสามารถเขียน

(defun my-find-file-advice-print-arguments (old-function &rest arguments)
  "Print the argument list every time the advised function is called."
  (print arguments)
  (apply old-function arguments))

(advice-add #'find-file :around #'my-find-file-advice-print-arguments)

ด้วยการใช้งานใหม่นี้ทุกสิ่งที่ความต้องการของคำแนะนำจะถูกส่งเป็นอาร์กิวเมนต์ ad-get-argsไม่จำเป็นเนื่องจากอาร์กิวเมนต์จะถูกส่งผ่านไปยังฟังก์ชันคำแนะนำเหมือนกับอาร์กิวเมนต์ของฟังก์ชันปกติ (สำหรับ WHEREอาร์กิวเมนต์ที่สมเหตุสมผล) ad-do-itกลายเป็นไม่จำเป็นตาม:aroundคำแนะนำที่ได้รับเป็นอาร์กิวเมนต์ฟังก์ชั่นและข้อโต้แย้งจึง(ad-do-it)ถูกแทนที่ด้วยแบบฟอร์ม

(apply old-function arguments)

หรือเมื่อคุณตั้งชื่อข้อโต้แย้ง

(funcall old-function first-arg second-arg)

ซึ่งสะอาดกว่าเนื่องจากไม่มีรูปแบบเวทมนตร์ที่เกี่ยวข้อง การแก้ไขข้อโต้แย้งเกิดขึ้นเพียงแค่ส่งค่าที่แก้ไขไปOLD-FUNCTIONแล้ว

WHEREค่าอื่น ๆ

docstring ของadd-functionมีตารางของสถานที่ให้คำแนะนำทั้งหมด (หรือ "combinators") และสิ่งที่พวกเขาจะเทียบเท่าและอธิบายการทำงานในแง่ของlambdaพฤติกรรมเทียบเท่ากับฟังก์ชั่นที่แนะนำ:

`:before'       (lambda (&rest r) (apply FUNCTION r) (apply OLDFUN r))
`:after'        (lambda (&rest r) (prog1 (apply OLDFUN r) (apply FUNCTION r)))
`:around'       (lambda (&rest r) (apply FUNCTION OLDFUN r))
`:override'     (lambda (&rest r) (apply FUNCTION r))
`:before-while' (lambda (&rest r) (and (apply FUNCTION r) (apply OLDFUN r)))
`:before-until' (lambda (&rest r) (or  (apply FUNCTION r) (apply OLDFUN r)))
`:after-while'  (lambda (&rest r) (and (apply OLDFUN r) (apply FUNCTION r)))
`:after-until'  (lambda (&rest r) (or  (apply OLDFUN r) (apply FUNCTION r)))
`:filter-args'  (lambda (&rest r) (apply OLDFUN (funcall FUNCTION r)))
`:filter-return'(lambda (&rest r) (funcall FUNCTION (apply OLDFUN r)))

(cited from `C-h f add-function')

โดยที่ FUNCTION เป็นฟังก์ชันคำแนะนำและ OLDFUN เป็นฟังก์ชันที่เพิ่มคำแนะนำไว้ อย่าพยายามทำความเข้าใจกับพวกเขาทั้งหมดในครั้งเดียวเพียงเลือกWHEREสัญลักษณ์ที่ฟังดูเหมาะสมและพยายามเข้าใจสิ่งนั้น

:aroundหรือการใช้งานเพียงแค่ เท่าที่ผมสามารถบอกได้เปรียบเพียงอย่างเดียวของการใช้ความWHEREเหนือ:aroundสำหรับทุกสิ่งที่คุณได้รับข้อมูลอีกเล็กน้อยจากการมองขึ้นC-h f ADVISED-FUNCTION ก่อนที่จะมีการอ่าน docstring ของคำแนะนำที่ นอกจากว่าคุณวางแผนที่จะเผยแพร่รหัสที่มีคำแนะนำมันอาจไม่สำคัญ

ฟังก์ชั่นคำแนะนำที่มีชื่อ

ฉันขอแนะนำให้ใช้ฟังก์ชั่นที่มีชื่อเป็นคำแนะนำเนื่องจากมันมีข้อดีหลายประการ (บางฟังก์ชั่นเหล่านี้ยังใช้กับการใช้ฟังก์ชั่นที่มีชื่อสำหรับ hooks):

  • มันแสดงให้เห็นในC-h f find-fileฐานะ

    :around advice: `my-find-file-advice-print-arguments'
    

    การลิงก์ไปยังนิยามของฟังก์ชันคำแนะนำซึ่งตามปกติจะมีลิงก์ไปยังไฟล์ที่มีการกำหนดไว้ หากคำแนะนำถูกกำหนดเป็นlambdaแบบฟอร์มโดยตรงในadvice-add แบบฟอร์ม docstring จะแสดงแบบอินไลน์ (เป็นระเบียบสำหรับ docstrings ยาว?) และไม่มีอะไรจะระบุว่ามันถูกกำหนดไว้ที่ไหน

  • คุณสามารถลบคำแนะนำด้วย

    (advice-remove #'find-file #'my-find-file-advice-print-arguments)
    
  • คุณสามารถอัปเดตคำจำกัดความของคำแนะนำได้โดยไม่ต้องเรียกใช้ซ้ำ advice-addหรือเสี่ยงต่อการใช้งานเวอร์ชันเก่า (เนื่องจากการรัน advice-addด้วยการเปลี่ยนแปลงlambdaจะได้รับการยอมรับว่าเป็นคำแนะนำใหม่

หมายเหตุ Side#'functionสัญกรณ์เป็นพื้นเทียบเท่ากับการ 'functionยกเว้นว่ามันช่วยให้คอมไพเลอร์ไบต์ระบุสัญลักษณ์ชื่อฟังก์ชั่นและทำให้การแจ้งฟังก์ชั่นที่ขาดหายไป (เช่นเนื่องจากการพิมพ์ผิด)


เป็นต่อการสนทนาที่ฉันมีกับสตีเฟ่น Monnier, คำพูดกัญชาไม่ควรที่จะใช้ที่นี่ในการขัดแย้งทั้งหมด .. มันควรจะเป็นและในทำนองเดียวกัน(advice-add 'find-file :around #'my-find-file-advice-print-arguments) (advice-remove 'find-file #'my-find-file-advice-print-arguments)
Kaushal Modi

ฉันเดาว่าadvice-addเป็นกรณีชายแดน โดยส่วนตัวแล้วฉันพิจารณาความ' ↔ #'แตกต่างว่าส่วนใหญ่ช่วยในการระบุความผิดพลาดในชื่อฟังก์ชั่นดังนั้นที่นี่มันอาจจะขึ้นอยู่กับว่าหนึ่งคาดว่าฟังก์ชั่นที่จะกำหนดตามเวลาที่คำแนะนำจะเพิ่ม
kdb

@kdb ในที่สุดฉันก็พบสิ่งนี้ด้วยตัวเอง (หลังจากที่ฉันพบเอกสารadd-function) ฉันหวังว่าเอกสารจะทำให้ชัดเจนยิ่งขึ้น ฉันอาจหาวิธีแก้ไขมัน
PythonNut

@kdb คุณหมายถึง "มันแสดงให้เห็นในC-h f find-fileไม่C-x?
Peeja

@Peeja ใช่ถูกต้องแล้ว
kdb
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.