Spiffy - إطار واجهة Spiffy Perl المناسب لك
package Keen; use Spiffy -Base; field 'mirth'; const mood => ':-)'; sub happy { if ($self->mood eq ':-(') { $self->mirth(-1); print "Cheer up!"; } super; }
"Spiffy" هو إطار عمل ومنهجية للقيام بالبرمجة الشيئية (OO) في لغة Perl. يجمع Spiffy بين أفضل أجزاء Exporter.pm وbase.pm وmixin.pm وSUPER.pm في فئة أساسية سحرية واحدة. إنه يحاول إصلاح جميع القمل والثآليل الخاصة بـ Perl OO التقليدي، بطريقة نظيفة ومباشرة و(ربما يومًا ما) قياسية.
يستعير Spiffy أفكارًا من لغات OO الأخرى مثل Python وRuby وJava وPerl 6. كما يضيف بعض الحيل الخاصة به.
إذا ألقيت نظرة على CPAN، فهناك الكثير من الوحدات ذات الصلة بـ OO. عند بدء مشروع جديد، تحتاج إلى اختيار مجموعة الوحدات الأكثر منطقية، ثم تحتاج إلى استخدام تلك الوحدات في كل فصل من فصولك الدراسية. من ناحية أخرى، يحتوي Spiffy على كل ما قد تحتاج إليه في وحدة واحدة، ولن تحتاج إلى استخدامه إلا مرة واحدة في أحد فصولك الدراسية. إذا جعلت Spiffy.pm هي الفئة الأساسية للفئة الأساسية في مشروعك، فسيقوم Spiffy تلقائيًا بتمرير كل سحره إلى جميع الفئات الفرعية الخاصة بك. قد تنسى في النهاية أنك تستخدمه!
الفرق الأكثر وضوحًا بين Spiffy والفئات الأساسية الأخرى الموجهة للكائنات Perl هو أن لديها القدرة على تصدير الأشياء. إذا قمت بإنشاء فئة فرعية من Spiffy، فسيتم تصدير كل الأشياء التي يصدرها Spiffy تلقائيًا بواسطة فئتك الفرعية، بالإضافة إلى أي أشياء أخرى تريد تصديرها. وإذا قام شخص ما بإنشاء فئة فرعية من فئتك الفرعية، فسيتم تصدير كل هذه الأشياء تلقائيًا، وهكذا. فكر في الأمر على أنه "تصدير موروث"، ويستخدم صيغة مواصفات Exporter.pm المألوفة.
لاستخدام Spiffy أو أي فئة فرعية من Spiffy كفئة أساسية لفصلك، يمكنك تحديد الوسيطة -base
لأمر use
.
use MySpiffyBaseModule -base;
يمكنك أيضًا استخدام use base 'MySpiffyBaseModule';
بناء الجملة وكل شيء سيعمل بنفس الطريقة تمامًا. التحذير الوحيد هو أنه يجب تحميل Spiffy.pm بالفعل. وذلك لأن Spiffy يعيد توصيل Base.pm بسرعة للقيام بكل سحر Spiffy.
يتمتع Spiffy بدعم الخلطات المشابهة لـ Ruby مع الأدوار المشابهة لـ Perl6. تمامًا مثل base
يمكنك استخدام أي من الاستدعاءات التالية:
use mixin 'MySpiffyBaseModule'; use MySpiffyBaseModule -mixin;
لن يعمل الإصدار الثاني إلا إذا كانت الفئة التي يتم خلطها هي فئة فرعية من Spiffy. سيعمل الإصدار الأول في جميع الحالات، طالما تم تحميل Spiffy بالفعل.
للحد من الأساليب التي يتم الخلط بينها، استخدم الأدوار. (تلميح: تعمل تمامًا مثل قائمة المصدرين):
use MySpiffyBaseModule -mixin => qw(:basics x y !foo);
في لغة Perl الموجهة للكائنات، يعد كل روتين فرعي تقريبًا بمثابة طريقة. تقوم كل طريقة بتمرير الكائن إليها كوسيطة أولى لها. وهذا يعني عمليا أن كل روتين فرعي يبدأ بالسطر:
my $self = shift;
يوفر Spiffy آلية تصفية اختيارية بسيطة لإدراج هذا السطر نيابةً عنك، مما يؤدي إلى الحصول على كود أنظف. إذا وجدت أن الطريقة المتوسطة تحتوي على 10 أسطر من التعليمات البرمجية، فهذا يعني 10% من التعليمات البرمجية الخاصة بك! لتشغيل هذا الخيار، ما عليك سوى استخدام الخيار - Base
بدلاً من الخيار -base
، أو إضافة الخيار -selfless
. إذا كانت تصفية المصدر تشعرك بالتوتر، فلا تستخدم هذه الميزة. أنا شخصياً أجد ذلك مسبباً للإدمان في سعيي لكتابة تعليمات برمجية نظيفة وقابلة للصيانة.
إحدى الميزات المفيدة لـ Spiffy هي أنه يصدر وظيفتين: field
و const
التي يمكن استخدامها للإعلان عن سمات فصلك، وإنشاء طرق الوصول لها تلقائيًا. والفرق الوحيد بين الوظيفتين هو أنه لا يمكن تعديل سمات const
؛ وبالتالي فإن الولوج أسرع بكثير.
أحد الجوانب المثيرة للاهتمام في برمجة OO هو عندما تستدعي إحدى الطرق نفس الطريقة من فئة أصل. يُعرف هذا عمومًا باستدعاء الطريقة الفائقة. إن وسيلة بيرل للقيام بذلك قبيحة للغاية:
sub cleanup { my $self = shift; $self->scrub; $self->SUPER::cleanup(@_); }
يجعل Spiffy من السهل جدًا استدعاء الأساليب الفائقة. أنت فقط تستخدم الوظيفة super
. لا تحتاج إلى تمرير أي وسيطات لأنها تقوم بتمريرها لك تلقائيًا. إليك نفس الوظيفة مع Spiffy:
sub cleanup { $self->scrub; super; }
لدى Spiffy طريقة خاصة لتحليل الوسائط تسمى parse_arguments
، والتي يستخدمها أيضًا لتحليل الوسائط الخاصة به. يمكنك تحديد الوسائط المنطقية (المفردة) والوسيطات المقترنة، باستخدام طريقتين خاصتين تسمى boolean_arguments
و paired_arguments
. تسحب وسيطات التحليل القيم المنطقية والأزواج وتعيدها في تجزئة مجهولة، متبوعة بقائمة من الوسائط غير المتطابقة.
أخيرًا، يمكن لـ Spiffy تصدير بعض وظائف تصحيح الأخطاء WWW
و XXX
و YYY
و ZZZ
. كل واحد منهم ينتج تفريغ YAML للوسائط الخاصة به. يحذر WWW الإخراج، ويموت XXX مع الإخراج، ويطبع YYY الإخراج، ويعترف ZZZ بالإخراج. إذا لم يناسب YAML احتياجاتك، فيمكنك تحويل جميع عمليات التفريغ إلى تنسيق Data::Dumper باستخدام خيار -dumper
.
هذا أنيق!
ينفذ Spiffy فكرة جديدة تمامًا في لغة Perl. الوحدات التي تعمل كفئات موجهة للكائنات وتقوم أيضًا بتصدير الوظائف. ولكنه يأخذ مفهوم Exporter.pm خطوة أخرى إلى الأمام؛ فهو يسير على مسار @ISA
للفئة بالكامل ويحترم مواصفات التصدير لكل وحدة نمطية. نظرًا لأن Spiffy يستدعي وحدة المصدر للقيام بذلك، يمكنك استخدام جميع ميزات الواجهة الرائعة التي يتمتع بها المصدر، بما في ذلك العلامات والنفي.
يأخذ Spiffy جميع الوسائط التي لا تبدأ بشرطة لتشمل مواصفات التصدير.
package Vehicle; use Spiffy -base; our $SERIAL_NUMBER = 0; our @EXPORT = qw($SERIAL_NUMBER); our @EXPORT_BASE = qw(tire horn); package Bicycle; use Vehicle -base, '!field'; $self->inflate(tire);
في هذه الحالة، سيتم نقل Bicycle->isa('Vehicle')
وأيضًا كل الأشياء التي يصدرها Vehicle
و Spiffy
إلى Bicycle
، باستثناء field
.
يمكن أن يكون التصدير مفيدًا للغاية عندما تكون قد صممت نظامًا يحتوي على مئات الفئات، وتريد أن تتمكن جميعها من الوصول إلى بعض الوظائف أو الثوابت
or variables. Just export them in your main base class and every subclass
سوف تحصل على الوظائف التي يحتاجون إليها.
يمكنك فعل كل ما يفعله المُصدِّر تقريبًا لأن Spiffy يفوض المهمة إلى المُصدِّر (بعد إضافة بعض سحر Spiffy). يقدم Spiffy متغير @EXPORT_BASE
الذي يشبه @EXPORT
، ولكن فقط للاستخدامات التي تستخدم -base
.
إذا كنت قد قمت بالكثير من برمجة OO في لغة Perl، فمن المحتمل أنك استخدمت الوراثة المتعددة (MI)، وإذا كنت قد قمت بالكثير من برمجة MI، فمن المحتمل أن تواجه مشاكل وصداعًا غريبًا. تحاول بعض اللغات مثل Ruby حل مشكلات MI باستخدام تقنية تسمى mixins. في الأساس، تستخدم جميع فئات روبي الوراثة الفردية (SI) فقط، ثم تخلط الوظائف من الوحدات الأخرى إذا احتاجت إلى ذلك.
يمكن اعتبار Mixins على مستوى مبسط على أنه استيراد أساليب فئة أخرى إلى فئتك الفرعية. ولكن من وجهة نظر التنفيذ، فهذه ليست الطريقة الأفضل للقيام بذلك. Spiffy يفعل ما تفعله روبي. فهو يقوم بإنشاء فئة مجهولة فارغة، ويستورد كل شيء إلى تلك الفئة، ثم يقوم بربط الفئة الجديدة بمسار SI ISA الخاص بك. وبعبارة أخرى، إذا قلت:
package AAA; use BBB -base; use CCC -mixin; use DDD -mixin;
سينتهي بك الأمر بسلسلة وراثة واحدة من الفئات مثل هذا:
AAA << AAA-DDD << AAA-CCC << BBB;
AAA-DDD
و AAA-CCC
هما أسماء الحزم الفعلية للفئات التي تم إنشاؤها. الشيء الجميل في هذا الأسلوب هو أن الخلط في CCC لا يعرقل أي طرق في AAA، كما أن DDD لا يتعارض مع AAA أو CCC أيضًا. إذا قمت بخلط طريقة في CCC كانت أيضًا في AAA، فلا يزال بإمكانك الوصول إليها باستخدام super
.
عندما يمزج Spiffy في CCC، فإنه يسحب جميع الأساليب في CCC التي لا تبدأ بشرطة سفلية. في الواقع الأمر يذهب إلى أبعد من ذلك. إذا كانت CCC فئة فرعية، فسوف تستخدم كل الطرق التي can
لـ CCC القيام بها من خلال الميراث. هذا قوي جدًا، وربما قوي جدًا.
للحد من ما تخلطه، يستعير Spiffy مفهوم الأدوار من Perl6. يتم استخدام مصطلح الدور بشكل فضفاض في Spiffy بالرغم من ذلك. إنها تشبه إلى حد كبير قائمة الاستيراد التي تستخدمها وحدة المصدر، ويمكنك استخدام المجموعات (العلامات) والنفي. إذا كان العنصر الأول في قائمتك يستخدم النفي، فسيبدأ Spiffy بجميع الطرق التي يمكن لفصل mixin الخاص بك القيام بها.
use EEE -mixin => qw(:tools walk !run !:sharp_tools);
في هذا المثال، يعد walk
run
من الأساليب التي يمكن لـ EEE القيام بها، tools
و sharp_tools
عبارة عن أدوار للفئة EEE. كيف تحدد الفئة EEE هذه الأدوار؟ إنه يحدد بكل بساطة أساليب تسمى _role_tools
و_ _role_sharp_tools
والتي تعرض قوائم بمزيد من الأساليب. (وربما أدوار أخرى!) الشيء الجيد هنا هو أنه بما أن الأدوار هي مجرد طرق، فيمكن توريثها أيضًا. خذ هذا بيرل 6!
باستخدام العلامة -Base
بدلاً من -base
لن تحتاج أبدًا إلى كتابة السطر:
my $self = shift;
تتم إضافة هذا البيان إلى كل روتين فرعي في الفصل الدراسي الخاص بك باستخدام عامل تصفية المصدر. السحر بسيط وسريع، لذلك هناك عقوبة صغيرة على الأداء لإنشاء تعليمات برمجية نظيفة على قدم المساواة مع Ruby وPython.
package Example; use Spiffy -Base; sub crazy { $self->nuts; } sub wacky { } sub new() { bless [], shift; }
هو بالضبط نفس:
package Example; use Spiffy -base; use strict;use warnings; sub crazy {my $self = shift; $self->nuts; } sub wacky {my $self = shift; } sub new { bless [], shift; } ;1;
لاحظ أن الأقواس الفارغة بعد الروتين الفرعي new
تمنعه من إضافة $self. لاحظ أيضًا أنه تتم إضافة الكود الإضافي إلى الأسطر الموجودة لضمان عدم تغيير أرقام الأسطر.
- يقوم -Base
أيضًا بتشغيل القواعد الصارمة والتحذيرات، ويضيف ذلك المزعج "1؛" خط إلى الوحدة النمطية الخاصة بك.
يتمتع Spiffy الآن بدعم الأساليب الخاصة عند استخدام آلية التصفية "-Base". ما عليك سوى الإعلان عن المشتركين باستخدام الكلمة الرئيسية my
، ثم الاتصال بهم بعلامة '$'
في المقدمة. مثله:
package Keen; use SomethingSpiffy -Base; # normal public method sub swell { $self->$stinky; } # private lexical method. uncallable from outside this file. my sub stinky { ... }
تعد وظيفة XXX مفيدة جدًا لتصحيح الأخطاء لأنه يمكنك إدراجها في أي مكان تقريبًا، وسوف تقوم بتفريغ بياناتك في YAML نظيفة ولطيفة. خذ البيان التالي:
my @stuff = grep { /keen/ } $self->find($a, $b);
إذا كانت لديك مشكلة مع هذا البيان، فيمكنك تصحيحه بأي من الطرق التالية:
XXX my @stuff = grep { /keen/ } $self->find($a, $b); my @stuff = XXX grep { /keen/ } $self->find($a, $b); my @stuff = grep { /keen/ } XXX $self->find($a, $b); my @stuff = grep { /keen/ } $self->find(XXX $a, $b);
XXX سهل الإدخال والإزالة. ومن التقاليد أيضًا تحديد المناطق غير المؤكدة من التعليمات البرمجية بـ XXX. سيؤدي هذا إلى تسهيل اكتشاف شاحنات تصحيح الأخطاء إذا نسيت إخراجها.
يعد كل من WWW وYYY أمرًا رائعًا لأنهما يتخلصان من الوسائط الخاصة بهما ثم يعيدان الوسائط. بهذه الطريقة يمكنك إدراجها في العديد من الأماكن مع استمرار تشغيل الكود كما كان من قبل. استخدم ZZZ عندما تحتاج إلى الموت باستخدام كل من تفريغ YAML وتتبع المكدس الكامل.
يتم تصدير وظائف تصحيح الأخطاء بشكل افتراضي إذا كنت تستخدم الخيار -base
، ولكن فقط إذا كنت قد استخدمت الخيار -XXX
مسبقًا. لتصدير جميع الوظائف الأربع استخدم علامة التصدير:
use SomeSpiffyModule ':XXX';
لإجبار وظائف تصحيح الأخطاء على استخدام Data::Dumper بدلاً من YAML:
use SomeSpiffyModule -dumper;
يصف هذا القسم الوظائف التي يصدرها Spiffy. يتم تصدير الوظائف field
و const
و stub
و super
فقط عند استخدام الخيارات -base
أو -Base
.
مجال
يحدد طرق الوصول لحقل صفك:
package Example; use Spiffy -Base; field 'foo'; field bar => []; sub lalala { $self->foo(42); push @{$self->{bar}}, $self->foo; }
المعلمة الأولى التي تم تمريرها إلى field
هي اسم السمة التي يتم تعريفها. يمكن إعطاء الوصولات قيمة افتراضية اختيارية. سيتم إرجاع هذه القيمة إذا لم يتم تعيين قيمة للحقل في الكائن.
ثابت
const bar => 42;
الدالة const
تشبه الدالة <field> فيما عدا أنها غير قابلة للتغيير. كما أنه لا يقوم بتخزين البيانات في الكائن. ربما تريد دائمًا إعطاء قيمة افتراضية لـ const
، وإلا فإن الطريقة التي تم إنشاؤها ستكون عديمة الفائدة إلى حد ما.
كعب
stub 'cigar';
تقوم وظيفة stub
بإنشاء طريقة ستنتهي بالرسالة المناسبة. الفكرة هي أن الفئات الفرعية يجب أن تنفذ هذه الأساليب حتى لا يتم استدعاء الأساليب الأساسية.
ممتاز
إذا تم استدعاء هذه الدالة بدون أي وسيطات، فسوف تستدعي نفس الطريقة الموجودة بها، في أعلى شجرة ISA، وتمريرها بنفس الوسيطات. إذا تم استدعاؤه باستخدام الوسائط، فسوف يستخدم تلك الوسائط مع $self
في المقدمة. وبعبارة أخرى، فإنه يعمل كما كنت تتوقع.
sub foo { super; # Same as $self->SUPER::foo(@_); super('hello'); # Same as $self->SUPER::foo('hello'); $self->bar(42); } sub new() { my $self = super; $self->init; return $self; }
لن يفعل super
شيئًا ببساطة إذا لم تكن هناك طريقة فائقة. أخيرًا، يقوم super
بالشيء الصحيح في الإجراءات الفرعية AUTOLOAD.
يسرد هذا القسم كافة الأساليب التي ترثها أي فئة فرعية من Spiffy تلقائيًا.
mixin
طريقة لخلط فئة في وقت التشغيل. يأخذ نفس الحجج مثل use mixin ...
. يجعل الفئة المستهدفة مزيجًا من المتصل.
$self->mixin('SomeClass'); $object->mixin('SomeOtherClass' => 'some_method');
parse_arguments
تأخذ هذه الطريقة قائمة من الوسائط وتجميعها في أزواج. فهو يسمح بالوسائط المنطقية التي قد تكون أو لا تحتوي على قيمة (الافتراضي هو 1). تقوم الطريقة بإرجاع مرجع التجزئة لجميع الأزواج كمفاتيح وقيم في التجزئة. يتم إرجاع أية وسائط لا يمكن إقرانها كقائمة. هنا مثال:
sub boolean_arguments { qw(-has_spots -is_yummy) } sub paired_arguments { qw(-name -size) } my ($pairs, @others) = $self->parse_arguments( 'red', 'white', -name => 'Ingy', -has_spots => -size => 'large', 'black', -is_yummy => 0, );
بعد هذه المكالمة، سوف تحتوي $pairs
على:
{ -name => 'Ingy', -has_spots => 1, -size => 'large', -is_yummy => 0, }
وسيحتوي @others
على "أحمر" و"أبيض" و"أسود".
boolean_arguments
إرجاع قائمة الوسائط التي تم التعرف عليها على أنها منطقية. تجاوز هذه الطريقة لتعريف القائمة الخاصة بك.
Paired_arguments
إرجاع قائمة الوسائط التي تم التعرف عليها على أنها مقترنة. تجاوز هذه الطريقة لتعريف القائمة الخاصة بك.
عند use
وحدة Spiffy أو فئة فرعية منها، يمكنك تمرير قائمة من الوسائط إليها. يتم تحليل هذه الوسائط باستخدام طريقة parse_arguments
الموضحة أعلاه. يتم استخدام الوسيطة الخاصة -base
لجعل الحزمة الحالية فئة فرعية من الوحدة النمطية Spiffy المستخدمة.
أي معلمات غير مقترنة تعمل كقائمة استيراد عادية؛ تمامًا مثل تلك المستخدمة مع وحدة المُصدِّر.
الطريقة الصحيحة لاستخدام وحدة Spiffy كفئة أساسية هي استخدام المعلمة -base
في بيان use
. وهذا يختلف عن الوحدات النمطية النموذجية حيث قد ترغب في use base
.
package Something; use Spiffy::Module -base; use base 'NonSpiffy::Module';
الآن قد يكون من الصعب تتبع ما هو Spiffy وما هو ليس كذلك. لذلك تم تصميم Spiffy بالفعل للعمل مع base.pm. يمكنك أن تقول:
package Something; use base 'Spiffy::Module'; use base 'NonSpiffy::Module';
يعد use base
مفيدًا جدًا أيضًا عندما لا يكون فصلك وحدة نمطية فعلية (ملف منفصل) ولكنه مجرد حزمة في بعض الملفات التي تم تحميلها بالفعل. base
ستعمل سواء كانت الفئة وحدة نمطية أم لا، في حين أن بناء الجملة -base
لا يمكن أن يعمل بهذه الطريقة، لأن use
يحاول دائمًا تحميل وحدة نمطية.
لجعل Spiffy يعمل مع base.pm، تم لعب خدعة قذرة. base::import
بنسختها الخاصة. إذا لم تكن الوحدات الأساسية Spiffy، فسيقوم Spiffy باستدعاء القاعدة الأصلية::import. إذا كانت الوحدات الأساسية هي Spiffy، فإن Spiffy يقوم بعمله الخاص.
هناك نوعان من التحذيرات.
يجب تحميل Spiffy أولاً.
إذا لم يتم تحميل Spiffy وتم استدعاء use base
على وحدة Spiffy، فسيموت Spiffy برسالة مفيدة تخبر المؤلف بقراءة هذه الوثائق. وذلك لأن Spiffy كان بحاجة إلى إجراء مبادلة الاستيراد مسبقًا.
إذا حصلت على هذا الخطأ، فما عليك سوى وضع عبارة مثل هذه في المقدمة في التعليمات البرمجية الخاصة بك:
use Spiffy ();
لا خلط
يمكن أن يأخذ base.pm
وسيطات متعددة. ويعمل هذا مع Spiffy طالما أن جميع الفئات الأساسية هي Spiffy، أو جميعها غير Spiffy. إذا تم خلطهم، سوف يموت Spiffy. في هذه الحالة فقط استخدم عبارات use base
المنفصلة.
Spiffy هي طريقة رائعة للقيام ببرمجة OO في Perl، لكنها لا تزال قيد التقدم. ستتم إضافة أشياء جديدة، وقد تتم إزالة الأشياء التي لا تعمل بشكل جيد.
إنجي دوت نت <[email protected]>
حقوق الطبع والنشر 2004-2014. إنجي دوت نت.
هذا البرنامج هو برنامج مجاني. يمكنك إعادة توزيعه و/أو تعديله بنفس شروط لغة Perl نفسها.
راجع http://www.perl.com/perl/misc/Artistic.html