Ruby / التكامل: البيانات والموارد وأدلة التنفيذ والثقة / الدرس 14
امتلاك أعمار IO وحدود النص
استخدم موارد تملكها الكتلة وأمثلة StringIO وفحوص البايت والترميز واستهلاكا محدودا دون ادعاء تنفيذ ملفات فعلية.
في هذه الصفحة
أهداف الدرس
- ميّز مثال IO في الذاكرة من مورد نظام تشغيل وضمانات دوامه.
- اشرح اختلاف وسم الترميز والتحويل وصحة البايت وحدود الأسطر.
صرّح هل تستعير الواجهة المورد أم تغلقه
قد يتجاوز الدفق عمر استدعاء، فسم مالك فتحه واستخدامه وإغلاقه. تربط الصيغ الكتلية المناسبة الإغلاق بعمر الكتلة، ولا يغلق المساعد موردا مستعارا بصمت. تعتمد المسارات والأذونات والترميز وفشل التخزين على النظام والتنفيذ. يستخدم الدرس StringIO وبايتات الذاكرة فقط؛ ولا يقرأ ملفات أو ينفذ أوامر مضيف. لا يثبت تشابه الطرق تطابق الأخطاء والتخزين والدوام بين المثال و IO النظام.
افحص عقد إغلاق المثال نفسه
توفر StringIO عمليات شبيهة بـ IO على نص وتحتاج require في بيئة تملك المكتبة. تغلق صيغة open الكتلية الكائن عند النهاية. يحتفظ المثال بمرجع لفحص closed? فقط ولا يقرأ المغلق. تنتج each_line نصوص أسطر وتطبق strip تطبيعا تعليميا معلنا قبل الجمع، لا قاعدة حفظ أرشيف عامة. المخرج مستنتج من العقد لعدم توفر Ruby ومكتباتها للتنفيذ أثناء التأليف.
require 'stringio'
owned = nil
StringIO.open("one\ntwo\n", 'r') do |stream|
owned = stream
puts stream.each_line.map { |line| line.strip }.join(',')
end
puts owned.closed?
one,two
true
المخرج المتوقع one,two ثم true. يشرح إغلاق StringIO فقط لا ملفا أو واصف نظام. لم يُنفذ السكربت.
لا يصلح تغيير وسم الترميز البايتات
تغير force_encoding وسم البايتات القائمة، وتجري encode تحويلا وفق قواعدها. تفحص valid_encoding? صحة البايتات للوسم، ولا تثبت المعنى البشري أو التطبيع. يبني المثال تسلسل UTF-8 الصحيح لـé ويسم نسخة به. قد ينقسم المحرف متعدد البايت بين قطع خام؛ فيحتاج فك كل قطعة مستقلة عناية. لا تقطع البايت اعتباطيا وتفترض حد محرف صحيح.
افصل عدد البايتات عن تفسير المحارف
حجم البايتات المعبأة اثنان. بعد وسم النسخة UTF-8 يصح التسلسل ويكون محرفا واحدا وفق length. لا يصف ذلك كل وحدة يدركها المستخدم في نص عام. تحتاج البايتات الخاطئة رفضا أو استبدالا صريحا لا تخمين وسم. احفظ الأصل للمصدر عند الحاجة ولا تسجل محتوى حساسا لتشخيص الترميز. لا تفحص القيم المحلية مفكك ملف أو حلقة قراءة جزئية أو ترميز طرفية.
bytes = [0xC3, 0xA9].pack('C*')
text = bytes.dup.force_encoding(Encoding::UTF_8)
puts bytes.bytesize
puts text.valid_encoding?
puts text.length
2
true
1
المخرج المتوقع 2 ثم true ثم 1. البايتات صحيحة معروفة ولا تحولها force_encoding أو تصلحها. لم يُنفذ فحص ترميز Ruby.
يحتاج التدفق حدود حجم واستهلاكا يوافق العمر
تتجنب each_line قراءة الملف كله دفعة، لكن سطرا هائلا أو to_a لاحقة قد يستهلكان ذاكرة كبيرة. حد المدخل والسجل والنتائج وفق المنتج. لا يعتمد المكرر الكسول موردا أغلقه منتجه. لا يضمن flush أو close معاملة أو نجاة عامة من انقطاع الطاقة. افحص الخروج المبكر والتشوه والنقص وفشل العملية والتنظيف معزولا ومخولا. لا تسجل الدورة فحص IO فعلي أو سلامة ملف أو إذن أو دوام.
الأخطاء الشائعة وإصلاحها
يفشل قارئ كسول بعد عودة طريقته المنتجة.
- لماذا يحدث؟
- أُغلق الدفق الذي تملكه الكتلة بالفعل.
- كيف تصلحه؟
- استهلك ضمن المالك أو صمّم مكررا يملك عمر المورد.
- كيف تتجنب تكراره؟
- راجع عمر المورد مع التقييم المؤجل.
يُعد وسم ترميز جديد إصلاحا للنص.
- لماذا يحدث؟
- اختلطت force_encoding بالتحويل أو التحقق.
- كيف تصلحه؟
- افحص الصحة واستخدم التحويل أو الرفض المقصود.
- كيف تتجنب تكراره؟
- أدرج بايتات خاطئة ولا تختبر الوسم وحده.
يستنفد استيراد سطري الذاكرة.
- لماذا يحدث؟
- لم يحد طول السجل أو تجسيد النتائج لاحقا.
- كيف تصلحه؟
- حد التراكم والمجموعات المحفوظة صراحة.
- كيف تتجنب تكراره؟
- اختبر التجاوز والتوقف المبكر معزولا.
اختبر فهمك
1. لماذا لا يغلق المساعد كل دفق يتلقاه دائما؟
اعرض الحل المشروح
قد يملكه المستدعي ويحتاجه لاحقا، فيغير إغلاق المستعار العقد ويكسر عملا آخر. أعلن نقل الملكية ودع المالك يعالج الإتمام والتنظيف. لا تمنح سهولة ensure الملكية بذاتها.
2. هل تثبت valid_encoding? صحة عنوان الأرشيف دلاليا؟
اعرض الحل المشروح
لا. تفحص البايتات للترميز، لا المحتوى أو التطبيع أو الإذن أو ارتباط العنوان بالسجل. افحص المجال منفصلا واحفظ المصدر عند الحاجة. ولا يثبت حتى نجاح مثال ذاكرة قراءة ملف حقيقي أو إغلاقه صحيحا.
أهم ما تعلمته
- ملكية المورد وصحة النص والإتمام الدائم عقود منفصلة.
- يثبت مثال IO السلوك الذي ينمذجه فقط.