كيف يمكنني الالتفاف على مكالمة "الموت" في مكتبة بيرل لا يمكنني تعديلها؟
-
19-08-2019 - |
سؤال
نعم ، المشكلة هي مع مكتبة أستخدمها ، ولا ، لا يمكنني تعديلها. أحتاج إلى حل بديل.
في الأساس ، أنا أتعامل مع مكتبة بيرل مكتوبة بشكل سيء ، والتي تخرج مع "الموت" عند مواجهة حالة خطأ معينة في قراءة ملف. أسمي هذا الروتين من برنامج يحلق من خلال الآلاف من الملفات ، حفنة منها سيئة. ملفات سيئة تحدث ؛ أريد فقط أن يقوم روتيني بتسجيل خطأ ويتحرك.
إذا كان بإمكاني تعديل المكتبة ، فسأقوم ببساطة بتغيير
die "error";
إلى
print "error";return;
, ، لكن انا لا استطيع. هل هناك أي طريقة يمكنني من خلالها أريكة الروتين حتى لا تصطدم الملفات السيئة بالعملية بأكملها؟
سؤال المتابعة: استخدام "eval" لأحواض المكالمة المعرضة للتصادم يعمل بشكل جيد ، ولكن كيف يمكنني إعداد معالجة الأخطاء القابلة للقبض في هذا الإطار؟ لوصف:
لدي روتين فرعي يطلق على المكتبة-التي تُعزى في بعض الأحيان. بدلاً من الأريكة ، كل مكالمة داخل هذه الروتين الفرعي مع eval {} ، أسمح لها فقط بالموت ، واستخدام eval {} على المستوى الذي يستدعي روتين الفرعي الخاص بي:
my $status=eval{function($param);};
unless($status){print $@; next;}; # print error and go to next file if function() fails
ومع ذلك ، هناك شروط خطأ يمكنني القيام بها في الوظيفة (). ما هي الطريقة الأكثر ملاءمة/أناقة لتصميم اللقاح للأخطاء في الروتين الفرعي وروتين الاتصال بحيث أحصل على السلوك الصحيح لكل من الأخطاء التي تم صيدها وغير الملتوية؟
المحلول
يمكنك لفه في eval
. نرى:
perldoc -f eval
على سبيل المثال ، يمكنك الكتابة:
# warn if routine calls die
eval { routine_might_die }; warn $@ if $@;
سيؤدي ذلك إلى تحويل الخطأ المميت إلى تحذير ، وهو ما اقترحته إلى حد ما. إذا die
يسمى، $@
يحتوي على السلسلة التي مرت عليها.
نصائح أخرى
هل هو فخ $SIG{__DIE__}
؟ إذا كان الأمر كذلك ، فهو محلي أكثر مما أنت عليه. ولكن هناك استراتيجيات زوجين:
يمكنك استحضار الحزمة و تجاوز موت:
package Library::Dumb::Dyer; use subs 'die'; sub die { my ( $package, $file, $line ) = caller(); unless ( $decider->decide( $file, $package, $line ) eq 'DUMB' ) { say "It's a good death."; die @_; } }
إذا لم يكن كذلك ، يمكن فخ هو - هي. (ابحث عن $ sig على الصفحة ، لا يتعامل Markdown مع الرابط الكامل.)
my $old_die_handler = $SIG{__DIE__}; sub _death_handler { my ( $package, $file, $line ) = caller(); unless ( $decider->decide( $file, $package, $line ) eq 'DUMB DIE' ) { say "It's a good death."; goto &$old_die_handler; } } $SIG{__DIE__} = \&_death_handler;
قد تضطر إلى مسح المكتبة ، والعثور على فرع دائماً المكالمات ، واستخدم ذلك لتحميل الخاص بك
$SIG
معالج عن طريق تجاوزthat
.my $dumb_package_do_something_dumb = \&Dumb::do_something_dumb; *Dumb::do_something_dumb = sub { $SIG{__DIE__} = ... goto &$dumb_package_do_something_dumb; };
أو تجاوز مصممة دائماً المكالمات...
package Dumb; use subs 'chdir'; sub chdir { $SIG{__DIE__} = ... CORE::chdir @_; };
إذا فشل كل شيء آخر ، فيمكنك ضرب عيون الحصان بهذا:
package CORE::GLOBAL; use subs 'die'; sub die { ... CORE::die @_; }
هذا سوف يتجاوز موت على الصعيد العالمي ، الطريقة الوحيدة التي يمكنك بها العودة die
هو معالجته كـ CORE::die
.
بعض مزيج من هذا سوف يعمل.
على الرغم من تغيير أ die
لعدم الموت له حل محدد كما هو موضح في الإجابات الأخرى ، بشكل عام يمكنك دائمًا تجاوز الروتين الفرعي في حزم أخرى. أنت لا تغير المصدر الأصلي على الإطلاق.
أولاً ، قم بتحميل الحزمة الأصلية حتى تحصل على جميع التعريفات الأصلية. بمجرد أن يكون الأصل في مكانه ، يمكنك إعادة تعريف الروتين الفرعي المزعج:
BEGIN {
use Original::Lib;
no warnings 'redefine';
sub Original::Lib::some_sub { ... }
}
يمكنك حتى قطع ولصق التعريف الأصلي وتعديل ما تحتاجه. إنه ليس حلاً رائعًا ، ولكن إذا لم تتمكن من تغيير المصدر الأصلي (أو ترغب في تجربة شيء ما قبل تغيير الأصل) ، فيمكنه العمل.
إلى جانب ذلك ، يمكنك نسخ الملف المصدر الأصلي إلى دليل منفصل للتطبيق الخاص بك. نظرًا لأنك تتحكم في هذا الدليل ، يمكنك تحرير الملفات فيه. يمكنك تعديل تلك النسخ وتحميلها عن طريق إضافة هذا الدليل إلى مسار البحث عن وحدة Perl:
use lib qw(/that/new/directory);
use Original::Lib; # should find the one in /that/new/directory
تتمسك نسختك حتى لو قام شخص ما بتحديث الوحدة الأصلية (على الرغم من أنك قد تضطر إلى دمج التغييرات).
أنا أتحدث عن هذا قليلا في إتقان بيرل, ، حيث أعرض بعض التقنيات الأخرى للقيام بهذا النوع من الأشياء. الحيلة هي عدم كسر الأشياء أكثر. كيف لا تكسر الأشياء تعتمد على ما تفعله.