מטפלי קובץ קשורים#

מטפל קובץ קשור מנתב מחדש קלט/פלט באותו אופן שבו סקלר קשור מנתב מחדש קריאות וכתיבות. הדפיסו אליו וה־PRINT שלכם רץ; קראו שורה וה־READLINE שלכם רץ. השימושים הקלאסיים הם הפניית פלט למקום לא־רגיל (אל מחרוזת, לרוחב רשת, דרך מסנן) והטמעת Perl בתוכנית מארחת שזקוקה לטיפול מיוחד ב־STDOUT וב־STDERR.

הממשק גדול יותר מהאחרים אך ברובו אופציונלי: אתם מממשים רק את הפעולות שהמטפל אכן יקבל. התפריט המלא נמצא בעמוד העזר tie; פרק זה בונה מחלקה ומסביר את הווים ואת תזמונם.

מחלקה שלמה#

מטפל לכתיבה בלבד שאוסף למחרוזת את כל מה שמודפס אליו:

use v5.36;

package Collector {
    sub TIEHANDLE { my $class = shift; my $buf = ''; return bless \$buf, $class }
    sub PRINT     { my $self = shift; $$self .= join($, // '', @_); return 1 }
    sub PRINTF    { my $self = shift; my $fmt = shift; $$self .= sprintf($fmt, @_); return 1 }
    sub buffer    { my $self = shift; return $$self }
}

tie *OUT, 'Collector';
print OUT "hello ";
print OUT "world\n";
printf OUT "%d items\n", 3;
my $obj = tied *OUT;
print $obj->buffer;
# hello world
# 3 items

העצם הוא הפניית סקלר שעברה blessed ומחזיקה את הטקסט שנצבר. אל מתודת ה־buffer הנוספת מגיעים דרך tied, לא דרך פעולת קלט/פלט כלשהי - זו הדרך הסטנדרטית שבה מחלקת tie חושפת פעולות ללא תחביר של מטפל קובץ.

קישור ה־glob, לא הסקלר#

הארגומנט הראשון אל tie עבור מטפל חייב להיות glob - הוא מתחיל בכוכבית:

  • כדי לקשור מטפל בעל שם: tie *OUT, 'Collector'.

  • כדי לקשור מטפל שמוחזק בסקלר $fh: tie *$fh, 'Collector'. כתיבת tie $fh, ... קושרת את הסקלר $fh, לא את המטפל שבתוכו - טעות נפוצה ומבלבלת.

חוזה המתודות#

TIEHANDLE classname, LIST

הבנאי; מחזיר הפניה שעברה blessed מכל סוג. הוא יכול להחזיק כל מצב פנימי שהמטפל זקוק לו.

PRINT this, LIST

תומך ב־print וב־say. הוא מקבל את הרשימה המודפסת. כבדו את $, (מפריד שדות הפלט) בין פריטים ואת $\ (מסיים רשומת הפלט) בסוף אם אתם רוצים נאמנות מלאה - print אינו מכניס אותם עבורכם.

PRINTF this, format, LIST

תומך ב־printf. הוא מקבל את מחרוזת הפורמט ואת הארגומנטים; העבירו אותם דרך sprintf בעצמכם.

WRITE this, scalar, length, offset

תומך ב־syswrite - הכתיבה הגולמית, מוכוונת ה־buffer, הנבדלת מ־PRINT.

READLINE this

תומך ב־<$fh> וב־readline. בהקשר סקלרי החזירו את השורה הבאה או undef בסוף הקלט; בהקשר רשימה החזירו את כל השורות הנותרות או רשימה ריקה. המחרוזות המוחזרות צריכות לכלול את מפריד רשומת הקלט $/, בהתאמה למה שמטפל אמיתי נותן לכם.

READ this, scalar, length, offset / GETC this

תומכים ב־read / sysread וב־getc בהתאמה.

OPEN, CLOSE, EOF, BINMODE, FILENO, SEEK, TELL

תומכים במובנים המתאימים כאשר משתמשים בהם על המטפל. מממשים את אלה שהגיוניים עבור המאגר התומך שלכם ומשמיטים את השאר.

DESTROY this / UNTIE this

ניקוי אופציונלי, זהה בתפקידו לסוגי ה־tie האחרים. מחלקת מטפל לעיתים קרובות סוגרת כאן את המשאב התומך שלה.

תזמון הקריאה#

  • print FH @list ו־say FH @listPRINT. say בנוסף עושה localise ל־$\ אל "\n" סביב הקריאה, ולכן PRINT שמכבד את $\ מטפל ב־say ללא מקרה מיוחד.

  • printf FH $fmt, @argsPRINTF.

  • syswrite FH, $buf, $len, $offWRITE.

  • <FH> / readline FHREADLINE, בהקשר הסובב.

  • read/sysreadREAD; getc FHGETC.

  • close FH, eof FH, binmode FH, seek, tell, fileno, open FH, ... → הוו באותיות רישיות המתאים כאשר הוא מוגדר.

הערה על STDERR: כאשר STDERR קשור, ה־PRINT שלו הוא מה שמנפיק אזהרות והודעות שגיאה. זמן הריצה משבית את ה־tie למשך אותה קריאה, כך שתוכלו לבצע warn מתוך PRINT בלי לעורר רקורסיה אינסופית.

מחלקה מינימלית ברת־קיימא#

אין מתודת חובה יחידה מעבר ל־TIEHANDLE - אתם מממשים את כל הפעולות שהמטפל יקבל. מטפל לפלט בלבד זקוק ל־TIEHANDLE בתוספת PRINT (ובדרך כלל PRINTF). מטפל לקלט בלבד זקוק ל־TIEHANDLE בתוספת READLINE (ואולי GETC / READ). פעולות שהוו שלהן חסר מתות בנקודת השימוש, ולכן הגדירו בדיוק את הקבוצה שהקוראים שלכם מפעילים.

הדרך הקלה: ירושה מ־Tie::StdHandle#

Tie::StdHandle (מסופק בתוך Tie::Handle) קושר מטפל אל מטפל בסיסי אמיתי: ה־OPEN שלו פותח קובץ ממשי וווי הקלט/פלט מעבירים אליו. ירשו ממנו ועקפו רק את הפעולות שאתם רוצים ליירט:

package Doubler {
    use Tie::StdHandle;
    our @ISA = ('Tie::StdHandle');
    sub READLINE {
        my $self = shift;
        my $line = $self->SUPER::READLINE;
        return defined $line ? $line . $line : undef;   # echo each line twice
    }
}

my $data = "a\nb\n";
tie *DUP, 'Doubler';
tied(*DUP)->OPEN('<', \$data);
print while defined($_ = <DUP>);
# a
# a
# b
# b

READLINE קורא כלפי מעלה אל מחלקת הבסיס עבור השורה הבאה האמיתית, ואז מכפיל אותה; כל פעולה אחרת זורמת דרך Tie::StdHandle ללא שינוי. Tie::Handle (ההורה) הוא הבסיס המופשט שמתעד את הממשק ומספק PRINT/PRINTF ברירת מחדל באמצעות WRITE; Tie::StdHandle הוא הקונקרטי, המוכן לשימוש.

ראו גם#

  • tie - המובנה ותפריט המתודות המלא של המטפל

  • tied - הדרך היחידה להגיע אל מתודות שאינן קלט/פלט של מחלקת מטפל, כמו buffer למעלה

  • print ו־printf - המובנים שמאחורי PRINT ו־PRINTF

  • readline - העמוד שלו מתעד את חוזה ההחזרה הסקלרי/רשימה ש־READLINE חייב לכבד

  • סקלרים קשורים - סוג ה־tie הפשוט ביותר, חימום טוב לקראת ממשק המטפל

  • Tie::Handle - מודול מחלקת הבסיס; Tie::StdHandle הוא הגרסה הקונקרטית