Keren - Kerangka Antarmuka Perl Keren Untuk Anda
package Keen; use Spiffy -Base; field 'mirth'; const mood => ':-)'; sub happy { if ($self->mood eq ':-(') { $self->mirth(-1); print "Cheer up!"; } super; }
"Spiffy" adalah kerangka kerja dan metodologi untuk melakukan pemrograman berorientasi objek (OO) di Perl. Spiffy menggabungkan bagian terbaik dari Eksportir.pm, base.pm, mixin.pm dan SUPER.pm menjadi satu kelas dasar ajaib. Ia mencoba memperbaiki semua kekurangan dan kelemahan Perl OO tradisional, dengan cara yang bersih, lugas, dan (mungkin suatu hari nanti) standar.
Spiffy meminjam ide dari bahasa OO lain seperti Python, Ruby, Java dan Perl 6. Ia juga menambahkan beberapa triknya sendiri.
Jika Anda melihat CPAN, ada banyak sekali modul terkait OO. Saat memulai proyek baru, Anda perlu memilih kumpulan modul yang paling masuk akal, lalu Anda perlu menggunakan modul tersebut di setiap kelas Anda. Spiffy, di sisi lain, memiliki semua yang mungkin Anda perlukan dalam satu modul, dan Anda hanya perlu menggunakannya sekali di salah satu kelas Anda. Jika Anda menjadikan Spiffy.pm sebagai kelas dasar dari kelas paling dasar dalam proyek Anda, Spiffy akan secara otomatis meneruskan semua keajaibannya ke semua subkelas Anda. Anda mungkin akhirnya lupa bahwa Anda sedang menggunakannya!
Perbedaan paling mencolok antara Spiffy dan kelas dasar berorientasi objek Perl lainnya adalah ia memiliki kemampuan untuk mengekspor sesuatu. Jika Anda membuat subkelas Spiffy, semua hal yang diekspor Spiffy akan secara otomatis diekspor oleh subkelas Anda, selain hal-hal lain yang ingin Anda ekspor. Dan jika seseorang membuat subkelas dari subkelas Anda, semua hal itu akan diekspor secara otomatis, dan seterusnya. Anggap saja sebagai "Ekspor yang Diwarisi", dan menggunakan sintaks spesifikasi Eksportir.pm yang sudah dikenal.
Untuk menggunakan Spiffy atau subkelas Spiffy mana pun sebagai kelas dasar kelas Anda, tentukan argumen -base
pada perintah use
.
use MySpiffyBaseModule -base;
Anda juga dapat menggunakan use base 'MySpiffyBaseModule';
sintaksis dan semuanya akan bekerja persis sama. Satu-satunya peringatan adalah Spiffy.pm harus sudah dimuat. Itu karena Spiffy memasang kembali base.pm dengan cepat untuk melakukan semua keajaiban Spiffy.
Spiffy memiliki dukungan untuk mixin mirip Ruby dengan peran mirip Perl6. Sama seperti base
Anda dapat menggunakan salah satu dari pemanggilan berikut:
use mixin 'MySpiffyBaseModule'; use MySpiffyBaseModule -mixin;
Versi kedua hanya akan berfungsi jika kelas yang digabungkan adalah subkelas dari Spiffy. Versi pertama akan berfungsi dalam semua kasus, selama Spiffy sudah dimuat.
Untuk membatasi metode yang tercampur, gunakan peran. (Petunjuk: cara kerjanya seperti daftar Eksportir):
use MySpiffyBaseModule -mixin => qw(:basics x y !foo);
Dalam Perl berorientasi objek, hampir setiap subrutin adalah sebuah metode. Setiap metode meneruskan objek ke metode tersebut sebagai argumen pertamanya. Itu berarti hampir setiap subrutin dimulai dengan baris:
my $self = shift;
Spiffy menyediakan mekanisme filter opsional yang sederhana untuk menyisipkan baris tersebut untuk Anda, sehingga menghasilkan kode yang lebih bersih. Jika menurut Anda metode rata-rata memiliki 10 baris kode, itu berarti 10% dari kode Anda! Untuk mengaktifkan opsi ini, Anda cukup menggunakan opsi - Base
alih-alih opsi -base
, atau tambahkan opsi -selfless
. Jika pemfilteran sumber membuat Anda mual, jangan gunakan fitur tersebut. Saya pribadi merasa ketagihan dalam pencarian saya untuk menulis kode yang bersih dan mudah dipelihara.
Fitur yang berguna dari Spiffy adalah ia mengekspor dua fungsi: field
dan const
yang dapat digunakan untuk mendeklarasikan atribut kelas Anda, dan secara otomatis menghasilkan metode pengakses untuknya. Satu-satunya perbedaan antara kedua fungsi tersebut adalah atribut const
tidak dapat diubah; dengan demikian pengaksesnya jauh lebih cepat.
Salah satu aspek menarik dari pemrograman OO adalah ketika suatu metode memanggil metode yang sama dari kelas induk. Hal ini umumnya dikenal sebagai pemanggilan metode super. Fasilitas Perl untuk melakukan ini sangat buruk:
sub cleanup { my $self = shift; $self->scrub; $self->SUPER::cleanup(@_); }
Keren membuatnya, eh, sangat mudah untuk memanggil metode super. Anda cukup menggunakan fungsi super
. Anda tidak perlu memberikan argumen apa pun karena argumen tersebut secara otomatis meneruskannya untuk Anda. Berikut fungsi yang sama dengan Spiffy:
sub cleanup { $self->scrub; super; }
Spiffy memiliki metode khusus untuk menguraikan argumen yang disebut parse_arguments
, yang juga digunakan untuk menguraikan argumennya sendiri. Anda mendeklarasikan argumen mana yang boolean (tunggal) dan mana yang berpasangan, dengan dua metode khusus yang disebut boolean_arguments
dan paired_arguments
. Argumen parse mengeluarkan boolean dan pasangan dan mengembalikannya dalam hash anonim, diikuti dengan daftar argumen yang tidak cocok.
Terakhir, Spiffy dapat mengekspor beberapa fungsi debugging WWW
, XXX
, YYY
dan ZZZ
. Masing-masing menghasilkan dump YAML yang berisi argumennya. WWW memperingatkan keluaran, XXX mati dengan keluaran, YYY mencetak keluaran, dan ZZZ mengakui keluarannya. Jika YAML tidak sesuai dengan kebutuhan Anda, Anda dapat mengalihkan semua dump ke format Data::Dumper dengan opsi -dumper
.
Itu keren!
Spiffy menerapkan ide yang benar-benar baru di Perl. Modul yang bertindak sebagai kelas berorientasi objek dan juga fungsi ekspor. Namun konsep Eksportir.pm mengambil satu langkah lebih jauh; ia menelusuri seluruh jalur @ISA
suatu kelas dan memenuhi spesifikasi ekspor setiap modul. Karena Spiffy memanggil modul Eksportir untuk melakukan hal ini, Anda dapat menggunakan semua fitur antarmuka mewah yang dimiliki Eksportir, termasuk tag dan negasi.
Spiffy mempertimbangkan semua argumen yang tidak dimulai dengan tanda hubung untuk memenuhi spesifikasi ekspor.
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);
Dalam hal ini, Bicycle->isa('Vehicle')
dan juga semua hal yang diekspor Vehicle
dan Spiffy
, akan masuk ke Bicycle
, kecuali field
.
Mengekspor bisa sangat membantu ketika Anda merancang sistem dengan ratusan kelas, dan Anda ingin semuanya memiliki akses ke beberapa fungsi atau konstanta.
or variables. Just export them in your main base class and every subclass
akan mendapatkan fungsi yang mereka perlukan.
Anda dapat melakukan hampir semua hal yang dilakukan Eksportir karena Spiffy mendelegasikan pekerjaan tersebut kepada Eksportir (setelah menambahkan beberapa keajaiban Spiffy). Spiffy menawarkan variabel @EXPORT_BASE
seperti @EXPORT
, tetapi hanya untuk penggunaan yang menggunakan -base
.
Jika Anda telah melakukan banyak pemrograman OO di Perl, Anda mungkin menggunakan Multiple Inheritance (MI), dan jika Anda telah melakukan banyak MI, Anda mungkin mengalami masalah aneh dan sakit kepala. Beberapa bahasa seperti Ruby, berupaya menyelesaikan masalah MI menggunakan teknik yang disebut mixin. Pada dasarnya, semua kelas Ruby hanya menggunakan Single Inheritance (SI), dan kemudian menggabungkan fungsionalitas dari modul lain jika diperlukan.
Mixin dapat dianggap secara sederhana seperti mengimpor metode kelas lain ke dalam subkelas Anda. Namun dari sudut pandang implementasi, itu bukanlah cara terbaik untuk melakukannya. Spiffy melakukan apa yang Ruby lakukan. Ini membuat kelas anonim yang kosong, mengimpor semuanya ke dalam kelas itu, dan kemudian menghubungkan kelas baru ke jalur SI ISA Anda. Dengan kata lain, jika Anda mengatakan:
package AAA; use BBB -base; use CCC -mixin; use DDD -mixin;
Anda berakhir dengan satu rantai warisan kelas seperti ini:
AAA << AAA-DDD << AAA-CCC << BBB;
AAA-DDD
dan AAA-CCC
adalah nama paket sebenarnya dari kelas yang dihasilkan. Hal yang menyenangkan tentang gaya ini adalah pencampuran dalam CCC tidak mengganggu metode apa pun di AAA, dan DDD juga tidak bertentangan dengan AAA atau CCC. Jika Anda menggabungkan metode di CCC yang juga ada di AAA, Anda masih bisa mengaksesnya dengan menggunakan super
.
Saat Spiffy bercampur di CCC, ia menggunakan semua metode di CCC yang tidak dimulai dengan garis bawah. Sebenarnya ini lebih dari itu. Jika CCC adalah subkelas, ia akan menarik setiap metode yang can
dilakukan CCC melalui pewarisan. Ini sangat kuat, mungkin terlalu kuat.
Untuk membatasi apa yang Anda campur, Spiffy meminjam konsep Peran dari Perl6. Istilah peran digunakan lebih longgar di Spiffy. Ini seperti daftar impor yang digunakan modul Eksportir, dan Anda dapat menggunakan grup (tag) dan negasi. Jika elemen pertama dari daftar Anda menggunakan negasi, Spiffy akan memulai dengan semua metode yang dapat dilakukan oleh kelas mixin Anda.
use EEE -mixin => qw(:tools walk !run !:sharp_tools);
Dalam contoh ini, walk
and run
adalah metode yang dapat dilakukan EEE, dan tools
serta sharp_tools
adalah peran kelas EEE. Bagaimana kelas EEE mendefinisikan peran ini? Ini dengan sangat sederhana mendefinisikan metode yang disebut _role_tools
dan _role_sharp_tools
yang mengembalikan daftar metode lainnya. (Dan mungkin peran lainnya!) Hal yang menarik di sini adalah karena peran hanyalah metode, maka peran tersebut juga dapat diwariskan. Ambil Perl6 itu !
Dengan menggunakan flag -Base
alih-alih -base
Anda tidak perlu menulis baris:
my $self = shift;
Pernyataan ini ditambahkan ke setiap subrutin di kelas Anda dengan menggunakan filter sumber. Keajaibannya sederhana dan cepat, sehingga ada sedikit penalti kinerja untuk membuat kode bersih setara dengan Ruby dan Python.
package Example; use Spiffy -Base; sub crazy { $self->nuts; } sub wacky { } sub new() { bless [], shift; }
sama persis dengan:
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;
Perhatikan bahwa paren kosong setelah subrutin new
mencegahnya menambahkan $self. Perhatikan juga bahwa kode tambahan ditambahkan ke baris yang ada untuk memastikan bahwa nomor baris tidak diubah.
-Base
juga mengaktifkan pragma ketat dan peringatan, dan menambahkan '1;' yang mengganggu itu baris ke modul Anda.
Spiffy sekarang memiliki dukungan untuk metode pribadi ketika Anda menggunakan mekanisme filter '-Base'. Anda cukup mendeklarasikan subs dengan kata kunci my
, dan memanggilnya dengan '$'
di depannya. Seperti ini:
package Keen; use SomethingSpiffy -Base; # normal public method sub swell { $self->$stinky; } # private lexical method. uncallable from outside this file. my sub stinky { ... }
Fungsi XXX sangat berguna untuk debugging karena Anda dapat memasukkannya hampir di mana saja, dan itu akan membuang data Anda ke YAML yang bagus dan bersih. Ambil pernyataan berikut:
my @stuff = grep { /keen/ } $self->find($a, $b);
Jika Anda mempunyai masalah dengan pernyataan ini, Anda dapat men-debugnya dengan salah satu cara berikut:
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 mudah untuk dimasukkan dan dilepas. Ini juga merupakan tradisi untuk menandai area kode yang tidak pasti dengan XXX. Ini akan membuat dumper debugging mudah dikenali jika Anda lupa mengeluarkannya.
WWW dan YYY bagus karena membuang argumennya dan kemudian mengembalikan argumennya. Dengan cara ini Anda dapat memasukkannya ke banyak tempat dan kode tetap berjalan seperti sebelumnya. Gunakan ZZZ saat Anda harus mati dengan dump YAML dan pelacakan tumpukan penuh.
Fungsi debugging diekspor secara default jika Anda menggunakan opsi -base
, tetapi hanya jika sebelumnya Anda telah menggunakan opsi -XXX
. Untuk mengekspor keempat fungsi gunakan tag ekspor:
use SomeSpiffyModule ':XXX';
Untuk memaksa fungsi debugging menggunakan Data::Dumper alih-alih YAML:
use SomeSpiffyModule -dumper;
Bagian ini menjelaskan fungsi ekspor Spiffy. Fungsi field
, const
, stub
dan super
hanya diekspor ketika Anda menggunakan opsi -base
atau -Base
.
bidang
Mendefinisikan metode pengakses untuk bidang kelas Anda:
package Example; use Spiffy -Base; field 'foo'; field bar => []; sub lalala { $self->foo(42); push @{$self->{bar}}, $self->foo; }
Parameter pertama yang diteruskan ke field
adalah nama atribut yang ditentukan. Pengakses dapat diberikan nilai default opsional. Nilai ini akan dikembalikan jika tidak ada nilai untuk bidang yang ditetapkan pada objek.
konstanta
const bar => 42;
Fungsi const
mirip dengan <field> hanya saja fungsi tersebut tidak dapat diubah. Itu juga tidak menyimpan data di objek. Anda mungkin selalu ingin memberikan nilai default pada const
, jika tidak, metode yang dihasilkan akan menjadi tidak berguna.
rintisan
stub 'cigar';
Fungsi stub
menghasilkan metode yang akan mati dengan pesan yang sesuai. Idenya adalah subkelas harus mengimplementasikan metode ini sehingga metode stub tidak dipanggil.
super
Jika fungsi ini dipanggil tanpa argumen apa pun, ia akan memanggil metode yang sama, yang terletak lebih tinggi di pohon ISA, dan meneruskan semua argumen yang sama. Jika dipanggil dengan argumen, ia akan menggunakan argumen dengan $self
di depannya. Dengan kata lain, ini berfungsi seperti yang Anda harapkan.
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
tidak akan melakukan apa pun jika tidak ada metode super. Terakhir, super
melakukan hal yang benar dalam subrutin AUTOLOAD.
Bagian ini mencantumkan semua metode yang diwarisi secara otomatis oleh subkelas Spiffy mana pun.
campuran
Sebuah metode untuk mencampur kelas saat runtime. Mengambil argumen yang sama seperti use mixin ...
. Menjadikan kelas target sebagai mixin dari pemanggil.
$self->mixin('SomeClass'); $object->mixin('SomeOtherClass' => 'some_method');
parse_argumen
Metode ini mengambil daftar argumen dan mengelompokkannya menjadi berpasangan. Hal ini memungkinkan argumen boolean yang mungkin memiliki atau tidak memiliki nilai (default ke 1). Metode ini mengembalikan referensi hash dari semua pasangan sebagai kunci dan nilai dalam hash. Argumen apa pun yang tidak dapat dipasangkan akan dikembalikan sebagai daftar. Berikut ini contohnya:
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, );
Setelah panggilan ini, $pairs
akan berisi:
{ -name => 'Ingy', -has_spots => 1, -size => 'large', -is_yummy => 0, }
dan @others
akan berisi 'merah', 'putih', dan 'hitam'.
boolean_arguments
Mengembalikan daftar argumen yang diakui sebagai boolean. Ganti metode ini untuk menentukan daftar Anda sendiri.
berpasangan_argumen
Mengembalikan daftar argumen yang diakui berpasangan. Ganti metode ini untuk menentukan daftar Anda sendiri.
Saat Anda use
modul Spiffy atau subkelasnya, Anda bisa meneruskannya daftar argumen. Argumen ini diurai menggunakan metode parse_arguments
yang dijelaskan di atas. Argumen khusus -base
, digunakan untuk menjadikan paket saat ini sebagai subkelas dari modul Spiffy yang digunakan.
Parameter yang tidak berpasangan berfungsi seperti daftar impor biasa; sama seperti yang digunakan dengan modul Eksportir.
Cara yang tepat untuk menggunakan modul Spiffy sebagai kelas dasar adalah dengan menggunakan parameter -base
pada pernyataan use
. Ini berbeda dari modul biasa di mana Anda ingin use base
.
package Something; use Spiffy::Module -base; use base 'NonSpiffy::Module';
Sekarang mungkin sulit untuk melacak apa yang keren dan apa yang tidak. Oleh karena itu Spiffy sebenarnya dibuat untuk bekerja dengan base.pm. Anda dapat mengatakan:
package Something; use base 'Spiffy::Module'; use base 'NonSpiffy::Module';
use base
juga sangat berguna ketika kelas Anda bukan modul sebenarnya (file terpisah) tetapi hanya sebuah paket dalam beberapa file yang telah dimuat. base
akan berfungsi baik kelasnya berupa modul atau bukan, sedangkan sintaks -base
tidak dapat berfungsi seperti itu, karena use
selalu mencoba memuat modul.
Untuk membuat Spiffy bekerja dengan base.pm, sebuah trik kotor telah dimainkan. Pertukaran keren base::import
dengan versinya sendiri. Jika modul dasar tidak keren, keren akan memanggil base::import asli. Jika modul dasarnya adalah Spiffy, maka Spiffy melakukan tugasnya sendiri.
Ada dua peringatan.
Keren harus dimuat terlebih dahulu.
Jika Spiffy tidak dimuat dan use base
dipanggil pada modul Spiffy, Spiffy akan mati dengan pesan berguna yang memberitahu penulis untuk membaca dokumentasi ini. Itu karena Spiffy perlu melakukan pertukaran impor terlebih dahulu.
Jika Anda mendapatkan kesalahan ini, cukup letakkan pernyataan seperti ini di depan kode Anda:
use Spiffy ();
Tanpa Pencampuran
base.pm
dapat menerima banyak argumen. Dan ini berfungsi dengan Spiffy selama semua kelas dasarnya adalah Spiffy, atau semuanya non-Spiffy. Jika tercampur, Spiffy akan mati. Dalam hal ini cukup gunakan pernyataan use base
terpisah.
Spiffy adalah cara yang bagus untuk melakukan pemrograman OO di Perl, namun masih dalam proses. Hal-hal baru akan ditambahkan, dan hal-hal yang tidak berfungsi dengan baik mungkin akan dihapus.
Ingy dot Net <[email protected]>
Hak Cipta 2004-2014. Ingy dot Net.
Program ini adalah perangkat lunak bebas; Anda dapat mendistribusikannya kembali dan/atau memodifikasinya dengan ketentuan yang sama seperti Perl itu sendiri.
Lihat http://www.perl.com/perl/misc/Artistic.html