اذهب إلى المحتوى

سارة طه

الأعضاء
  • المساهمات

    18
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    5

كل منشورات العضو سارة طه

  1. تعرّفنا في الدّرس السّابق على المجالات وكيفيّة استخدامها مع العبارات الشرطيّة. سنتعرّف في هذا الدّرس على أنواع الحلقات Loops المختلفة والتي يمكن استخدامها في روبي. تُستخدم الحواسيب عادةً لتنفيذ أوامر متكرّرة آليًّا. تكرار تنفيذ مهام متشابهة دون خطأ هي عمليّة من السّهل على الحواسيب فعلها على أتمّ وجه، على عكس الإنسان الذي غالبًا ما يفشل في ذلك. ولأن التكرار أحد الأمور الشّائعة في البرمجة فإن روبي توفّر عدّة طرق لتنفيذه تسمّى بالحلقات. تقوم الحلقات بتكرار تنفيذ بعض الشيفرة البرمجيّة بناءً على شروط أو حالات معيّنة. حلقة while أوّل نوع من الحلقات سنتعرّف عليه هو حلقة while. تقوم حلقة while بتكرار تنفيذ الشيفرة البرمجيّة الموجودة بداخلها متى صحّ شرط معيّن. لفهم الحلقة أكثر دعونا نأخذ مثالاً عليها. سنطبّق ما تعلّمناه في الدروس السّابقة ولتحسين برنامج لعبة إلقاء النّرد التي تعرّفنا عليها سابقًا. أنشئ ملفّ روبي وسمّه while.rb أو أيّ اسم تريد مع كتابة rb. في نهاية اسم الملف. واكتب الشيفرة البرمجيّة التالية به: number = 0 attempts = 0 while number < 6 number = rand(1..6) puts "You rolled #{number}" attempts += 1 end puts "It took you #{attempts} attempts to roll number 6" بدأنا أوّلاً بتعريف متغيّر باسم number ومتغيّر باسم attempts. وأعطينا المتغيّرين قيمة مبدئيّة صفر. سنستخدم المتغيّرين لاحقًا في حلقة while لذلك فنحتاج إلى تهيئتهما أوّلاً في بداية البرنامج قبل تنفيذ حلقة while. إن لم نفعل ذلك فسوف نحصل على رسالة خطأ Error إذا تم استخدامهما قبل حصولهما على قيمة. جرّب بنفسك حذف المتغيّرين وتنفيذ البرنامج وحاول تحليل رسالة الخطأ التي ستظهر إليك. بعد ذلك لدينا الحلقة تبدأ باستخدام كلمة while المفتاحيّة في السّطر الرّابع وتنتهي بـ end في السّطر الثّامن (تعرّفنا على end سابقًا عندما استخدمناها مع العبارات الشرطيّة). وبين while وend لدينا الشيفرة البرمجيّة التي نريد تكرار تنفيذها متى تحقّق شرط الحلقة الموجود بعد كلمة while. لدينا الشرط في هذه الحالة هو أن تكون قيمة المتغيّر number أقلّ من 6. أعتقد أنّك قد خمّنت كل هذا بمجرّد رؤيتك للبرنامج وقبل قراءة الشرح فمن السّهولة قراءة حلقة while كما لو كانت إنجليزيّة عاديّة. ببساطة نخبر روبي أنّ تنفّذ مجموعة الشيفرة البرمجيّة متى (while) كان المتغيّر number أقلّ من 6. الآن وحيث أنّ قيمة المتغيّر number هي صفر في البداية فستقوم الحلقة بتنفيذ الشيفرة البرمجيّة مرّة واحدة على الأقل لأنّها ستبدأ وقيمة number أقلّ من 6. الآن بالنّظر إلى الشيفرة البرمجيّة بداخل while والتي ستُنفّذ على الأقلّ مرّة واحدة نجد أنّها تبدأ بتعيين قيمة جديدة للمتغيّر number وهي قيمة عشوائيّة من الأرقام الصحيحة بين 1 و6. تقابل هذه الشيفرة عمليّة إلقائك للنّرد. بعد ذلك نستخدم أمر puts لطباعة نصّ على الشّاشة يخبر المستخدم أنّ ناتج إلقائه للنّرد هو الرقم النّاتج عن الاختيار العشوائي بين 1 و6. تقابل هذه عمليّة سقوط النّرد وظهور الرّقم النّاتج. في آخر سطر من هذه الحلقة سيتمّ زيادة قيمة المتغيّر attempts بواحد. تذكّر أنّ رمز =+ هذا يعني إضافة القيمة الموجودة على الجانب الأيمن إلى قيمة attempts الأصليّة وحفظ القيمة الجديدة في المتغيّر attempts. إذًا في حالتنا هذه تضيف روبي 1 إلى attempts في كلّ مرّة تُنفّذ الشيفرات. الآن إذا كان الرقم العشوائي النّاتج لا زال أقلّ من 6 فسيتمّ تنفيذ هذه الشيفرات الموجودة داخل حلقة while مجدّدًا، ممّا يعني تعيين رقم عشوائي جديد إلى المتغيّر number، طباعة هذه القيمة الجديدة ثمّ زيادة قيمة المتغيّر attempts بواحد. ثمّ التحقّق هل قيمة number الجديدة أقلّ من 6 وهكذا دواليك إلى أن تصبح قيمة المتغيّر number هي 6. حينها سيتمّ إيقاف الحلقة وطباعة الرسالة الموجودة في السطر 10 والتي تخبر المستخدم عدد المرّات التي ألقى فيها النّرد (والمتمثّلة في المتغيّر attempts) قبل أن يصل إلى الرّقم 6. جرّب تنفيذ هذا البرنامج بفتح الطرفيّة والوصول إلى المجلّد الذي يحتوي على الملفّ وكتابة أمر: ruby [file name] حيث [file name] هو اسم الملفّ الخاصّ بك. while.rb في حالتي. جرّب البرنامج أكثر من مرّة ولاحظ كيف تختلف المُخرجات Outputs في كلّ مرّة. حلقة until حلقات until تشبه إلى حدٍّ كبير حلقات while. الفرق هو أن حلقة until ستواصل التكرار إلى أن يتحقّق شرط معيّن. على عكس while التي تواصل التكرار متى كان الشرط متحقّقًا وتتوقّف عند عدم تحقّقه. لتوضيح الفكرة أكثر سنستعرض مثال على ذلك. أنشئ ملفّ جديد باسم until.rb أو أيّ اسم آخر واكتب به الشيفرة البرمجيّة التّالية: puts "Hello! Type something" input = "" until input == "goodbye" puts input.upcase input = gets.chomp end puts "Bye! Let's play again soon" أوّلاً بدأنا بطباعة رسالة للمستخدم ترشده إلى ما عليه فعله ومن جديد قمنا بإنشاء وتهيئة متغيّر باسم input والذي سوف يستقبل مُدخلات المستخدم. عيّننا للمتغيّر سلسلة فارغة لأن روبي ستُرجع خطأ إذا ذُكر المتغيّر للمرّة الأولى في الحلقة دون ذكر سابق له. الآن وبالنّظر إلى حلقة until نجد أنّ لدينا الكلمة المفتاحيّة until لبداية الحلقة وend لإنهائها. لدينا أيضًا بعد until الشرط الذي فور حدوثه ستتوقّف الحلقة عن تنفيذ الشيفرات الموجودة بداخلها. هذه المرّة فإنّه الشيفرة البرمجيّة الموجودة في حلقة until سيتمّ تكرار تنفيذها إلى أن (until) تكون قيمة المتغيّر input تساوي السلسلة "goodbye". تذكّر كيف أنّ السلسلة الافتراضيّة المعيّنة للمتغيّر input هي سلسلة فارغة، إذًا فإنّ الحلقة ستعمل على الأقلّ مرّة واحدة. بالنّظر إلى داخل الحلقة، نرى أنّنا نستخدم أوّلاً أمر puts لطباعة المُدخلات ونستخدم دالّة upcase لطباعة تلك المُدخلات بأحرف كبيرة Capital Letters. هل يمكن أن تخمّن ما هي القيمة الأولى التي ستُطبع عند تنفيذ البرنامج وقبل كتابتك أيّة مدخلات؟ أعتقد أنّك توقّعتها، سلسلة فارغة. في السطر التالي نقوم باستبدال القيمة الموجودة في المتغيّر input بالقيمة الجديدة التي سيدخلها المستخدم. تذكّر استخدمنا دالّة chomp للتخلّص من رمز Enter المضاف إلى نهاية المُدخل. هذه الحلقة ستُكرّر ما يُدخله المستخدم ولكن بحروف كبيرة إلى أن يدخل المستخدم goodbye. وعند حدوث ذلك فستتوقّف الحلقة عن العمل ويطبع البرنامج الرسالة الأخيرة الموجودة في السطر 9 لإخبار المستخدم بانتهاء اللّعبة. جرّب تنفيذ البرنامج. هل لاحظت كيف لا يطبع البرنامج كلمة goodbye بأحرف كبيرة عندما تكتبها؟ هل يمكنك جعل الحلقة تطبع goodbye بأحرف كبيرة أوّلاً ثم تتوقّف عن التنفيذ؟ المكررات سنتعرّف الآن على بعض أنواع المكرّرات Iterators. وهي عبارة عن بعض الدوال الخاصّة بـالمصفوفات، جداول التقطيع و المجالات التي تحدّثنا عنها في الدروس السّابقة وعملها يشبه عمل الحلقات العاديّة. دالة each أوّل دالّة سنتعرّف عليها هي دالّة each والتي يمكنك رؤيتها في المثال التّالي: (1..10).each do |number| puts "#{number} squared is #{number**2}" end المجال الموجود هنا يمثّل الأعداد الصحيحة من 1 إلى 10 مع وجود 10 ضمنها. وبعدها استخدمنا دالّة each عن طريق كتابتها بعد المجال وبين الاثنين نقطة والتي تمثّل طريقة استدعاء الدوال على أيّ كائن في روبي. وتنتهي بالكلمة المفتاحيّة end مجدّدًا. ما تفعله هذه الدّالّة هو تنفيذ الشيفرة البرمجيّة الموجودة بداخلها على كلّ (each) عنصر موجود في المجال. لاحظ القيمة الموجودة في السّطر الأوّل number الموجودة بين رمزي الأنبوب Pipe Symbols. تمثّل هذه القيمة ما يشبه المتغيّر المؤقّت لتخزين قيمة عنصر المجال وقت حدوث كلّ عمليّة تكرار. إذًا فستبدأ الدّالّة بتعيين قيمة للمتغيّر تساوي 1 ثمّ تُدخل تلك القيمة إلى السلسلة التابعة لأمر puts. بمجرّد تنفيذ هذا الأمر سيتمّ زيادة قيمة المتغيّر لتصبح 2 وتُنفّذ الدّالّة أمر puts من جديد. وستتابع الدّالّة فعل ذلك (أعني زيادة قيمة المتغيّر وتنفيذ أمر puts) حتّى تصل إلى أن تكون قيمة المتغيّر number هي10. إذًا فهذا المتغيّر يعتبر نوعًا ما ماسك مكان Placeholder لكلّ رقم في كلّ تكرار يحدث في الدالّة. الآن لنلق نظرة على الشيفرة الموجودة داخل الدّالّة. ما يفعله البرنامج هنا هو استخدام دالّة puts لطباعة النصّ الذي نريد على الشّاشة وخاصيّة الاستيفاء Interpolation لطباعة الرقم ليمكننا رؤية كل رقم في المجال بدءًا من 1 ونهايةً بـ 10 ثم يخبرنا أنّ الرقم مربّعًا يساوي قيمة الاستيفاء الثّانية {number**2}#. تعرّفنا في درس التّعامل مع الأرقام أنّ رمز النّجمة يمثّل عمليّة الضرب. الآن أخبرك أن رمزي النّجمة معًا يمثّلان الأُسّ Power. إذًا فإنّ number**2 تعني number أسّ 2 أو قيمة number مربّعة. أو بشكل آخر number number. دالة map تشبه دالّة map دالّة each. ولكن بدلاً من مجرّد تنفيذ الشيفرة البرمجيّة بداخلها فإنّها تقوم أيضًا بإنشاء مصفوفة جديدة (أو جدول تقطيع) يحتوي نتائج تنفيذ الشيفرة الموجودة بداخلها على المصفوفة التي تم تنفيذها عليها. كما أنه بإمكانها باستبدال القيمة الأصليّة بداخل المصفوفة أو جدول التقطيع بالقيمة النّاتجة عن الشيفرة الموجودة داخل المكرّر أو الدّالّة map في حال ما إذا أضفنا علامة التّعجّب إلى اسم الدّالة لتصبح !map. لنستعرض المثال التّالي لتوضيح مبدأ عمل هذه الدّالّة: fruits = ["apples", "oranges"] fruits.map! { |fruit| "I like " + fruit } p fruits يمكننا أن نرى في المثال أنّ لدينا مصفوفة من سلسلتين معيّنة للمتغيّر fruits. الآن نريد أن نضيف I like قبل كلّ عنصر في هذه المصفوفة. كل ما علينا فعله هو استخدام الدّالّة map والتي سوف تكرّر تنفيذ الشيفرة البرمجيّة الموجودة بداخلها على كلّ عنصر في المصفوفة. لاحظ كيف استخدمنا الحاضنات Curly Braces هذه المرّة لوضع الشيفرة البرمجيّة بينها بدلاً من do وend. هذه الطريقة شائعة الاستخدام إذا كانت الشيفرة البرمجيّة مكوّنة من سطر واحد وذلك يوفّر عليك وضع end في سطر جديد. لاحظ لدينا من جديد المتغيّر المؤقّت واسمه هنا fruit والذي سيشير إلى كلّ عنصر موجود في المصفوفة. إذًا فلكلّ عنصر في المصفوفة سنقوم بإضافة السلسلة "I like" قبله. بعد ذلك استخدامنا دالّة + لإضافة السلسلة الجديدة إلى العنصر الذي تُنفّذ عليه الدّالّة. لن تطبع الدّالّة ذلك على الإطلاق فليس لدينا أمر puts أو أيّ شيء يؤدّي إلى تنفيذ عمليّة الطباعة. ستقوم الدّالّة فقط باستبدال العنصر الموجود في المصفوفة بالقيمة التي تُرجعها الشيفرة البرمجيّة الموجودة في الدّالّة. إذًا فنتوقّع تغيّر قيمة المصفوفة الأصليّة إلى التّالي: ["I like apples", "I like oranges"] ولاحظ كيف استخدمنا نسخة Bang للدّالّة map. وذلك بإضافة علامة تعجّب أو ما يسمّى برمز Ban إلى اسم الدّالّة. فعل هذا يعني أن المصفوفة سوف تُستبدل بالكامل. إذا لم نضع علامة Bang فكانت الدّالّة ستقوم بتنفيذ الشيفرات على عناصر المصفوفة وإنشاء/إرجاع مصفوفة مؤقّتة ولكن لم تكن لتستبدل المصفوفة الأصليّة الموجودة في المتغيّر fruits. في حالتنا وحيث أنّنا استخدمنا Bang فسيتمّ تغيير المصفوفة الأصليّة وحفظها في fruits. السّطر الأخير من الشيفرات يستخدم أمر p والذي يستخدم هنا لإظهار كيف أصبح المصفوفة بعد تغييرها. يستخدم أمر p غالبًا عند تنقيح الشيفرة البرمجيّة. حيث أنّه سيُظهر الكائن بدلاً من تحويله إلى سلسلة. هو مشابه جدًا لأمر puts. ولكن في حين أنّ puts يطبع دائمًا سلسلة على الشّاشة حيث أنّه اختصار لـ put string، فإنّ أمر p يُظهر الكائن تمامًا كما هو. إذًا فإنّه في المثال أعلاه بإمكاننا باستخدام p لرؤية المصفوفة fruits كمصفوفة. جرّب تنفيذ البرنامج وألق نظرة على المصفوفة الجديدة بعد التّعديل. خاتمة تعرّفنا في هذا الدّرس على مفهوم الحلقات وأنواعها ويمكنك التعرّف عليها أكثر عن طريق قراءة توثيق روبي عنها. تعرّفنا أيضًا على المكرّرات المستخدمة مع المصفوفات، جداول التقطيع والمجالات. أقترح عليك تحسين أحد البرامج المستخدمة في هذا الدّرس، مثلاً جرّب تعديل المثال المستخدم في حلقة until بحيث يستقبل كلمة goodbye على أيّ هيئة ويتحقّق الشرط وتتوقف الحلقة عن التنفيذ (أعني عند كتابة المستخدم Goodbye ،GOODBYE أو GoodBye أو غير ذلك من صور الكلمة يعتبر البرنامج أنّ الشرط قد تحقّق ويوقف اللّعبة). إذا كان لديك تساؤل أو تريد مشاركتنا ما طبّقت لا تتردّد في استخدام قسم التعليقات أدناه.
  2. تعرّفنا في الدّرس السّابق على جداول التّقطيع Hash وكيفيّة التعامل معها والدوال الخاصّة بها. سنتعرّف في هذا الدّرس على نوع آخر من المجموعات Collections وهو المجالات Ranges. تعدّ المجالات شكلًا آخر من المصفوفات Arrays التي تحدّثنا عنها في الدّرس الخامس إلا أنّها متسلسلة على نحوٍ محدّد وأسهل بكثير من حيث الإنشاء عن المصفوفات. أمثلة على المجالات، الأعداد من 0 لـ 9، الأيّام من السبت إلى الجمعة وغيرها من الأمثلة التي تقدّم مجالات محدّدة ومتسلسلة. إنشاء مجال سنتعرّف الآن على كيفيّة إنشاء المجالات في سطر أوامر روبي التفاعليّ. يمكن استخدام المجال لتمثيل متسلسلة من القيم بترتيب معيّن. ربّما تكون قد لاحظت استخدامنا للمجالات في دروس سابقة مثلما فعلنا عند البحث عن مصفوفة جزئيّة Subset من مصفوفة أخرى في درس المصفوفات. أوّلاً إحدى طرق إنشاء مجال هي نفس الطريقة التي استخدمناها لإنشاء مصفوفات وجداول التّقطيع من قبل عن طريق استخدام دالّة new. numbers = Range.new(1, 10) انتبه إلى أنّ دالّة new في حالة المجالات يجب أن تستقبل معطيات تمثّل بداية ونهاية المجال ولا يمكن إنشاء مجال فارغ مثلما كان ممكنًا إنشاء مصفوفات أو جداول تجزئة فارغة. جرّب كتابة الأمر السّابق مع عدم إعطاء روبي بداية ونهاية المجال، ماذا حدث؟ طبعت روبي رسالة خطأ Error تخبرك بأنّ عدد المعطيات خاطئة حيث أنّك زوّدت الدّالّة بلا شيء رغم انتظارها لمعطيين أو ثلاثة. المعطى الثالث exclude_end وهو لإخبار روبي هل عليها تضمين نهاية المجال بالمجال أم لا. إذا لم نعطي روبي ذلك المعطى الثّالث أو كانت قيمته false فستقوم روبي بتضمين النهاية بالمجال، أمّا في حالة غير ذلك فسيتمّ عدم تضمين النهاية. يمكنك إنشاء مجال عن طريقة الفصل بين بداية المجال ونهايتها باستخدام نقطتين كالتّالي: numbers = 1..10 سيقوم الأمر السّابق بإنشاء مجال من كلّ الأرقام الموجودة بين 1 و 10 مشتملة على 1 و 10 أيضًا وتعيينها إلى المتغيّر numbers. على الجانب الآخر فإنّه إذا استخدمنا ثلاث نقاط بدلاً من اثنتين ستقوم روبي بإنشاء مجال من العناصر من 1 إلى 9 مع تجاهل 10. 1...10 إذا فنستخدم النقطتان إذا أردنا أن يشتمل المجال على نقطة النّهاية وثلاث نقاط إذا لم نرده ذلك. يسمّى النّوع الأوّل Inclusive والثّاني Exclusive. يمكننا أيضًا إنشاء مجال محدّد من الأحرف. فمثلاً يمكننا إنشاء مجال للأبجديّة الإنجليزيّة مكوّن من الأحرف الصغيرة Lower Case ثمّ تعيينها إلى المتغيّر alphabet عن طريق كتابة الشيفرة البرمجيّة أدناه: alpahabet = "a".."z" إذًا لدينا المتغيّر alphabet والذين قمنا بتعيين المجال إليه. ومجالنا المحدّد هنا هو الأحرف من a إلى z مع تضمين z في المجال. الوصول إلى قيم بالمجال لاحظ كيف قامت روبي في كلّ مرّة بإرجاع المجال بالشّكل التي أُنشئت عليه دون طباعة عناصر المجال. هذا هو أحد الأمور المثيرة للاهتمام حول المجالات، فمتى أردت إظهار المجال حتّى ولو باستخدام الأمر puts فلن تحصل على شيء غير الهيئة التي أنشأت المجال عليها. قد تتساءل ولكن ماذا لو أردت استخدام عناصر المجال؟ للأسف لا يمكنك الوصول إلى العناصر أو القيم الموجودة في المجال مثلما كان بإمكانك مع المصفوفات والتجزئات. فمثلاً إذا أردت معرفة ما هو الحرف الموجود في الموقع الثّاني من المجال وكتبت [alphabet[2 مثلما كنت تفعل مع المصفوفة ستقوم روبي بإرجاع رسالة خط إليك. لأنّ هذه الدّالّة ليست دالّة للوصول إلى قيم مفردة في المجال. ولكن لحسن الحظ فهناك دالّة تسمّى to_a والتي تعني To Array. يمكن لهذه الدّالّة تحويل المجال الخاصّ بنا إلى مصفوفة ومن ثمّ يمكننا الوصول إلى العناصر بسهولة. alphabet_array = alphabet.to_a إذًا الآن لدينا المتغيّر alphabet_array والذي سيحتوي على المصفوفة الجديدة الناتجة عن تحويل المجال alphabet إلى مصفوفة باستخدام دالّة to_a. لاحظ كيف قامت روبي بإرجاع مصفوفة تحتوي على جميع الأحرف من a إلى z على هيئة عناصر من نوع سلسلة String. الآن يمكنك استخدام جميع الدوال الخاصّة بالمصفوفات والتي من بينها الوصول إلى العناصر. alphabet_array[2] ستقوم روبي بعد تنفيذ هذا الأمر بإرجاع "c". هذا لأنّه كما ذكرنا سابقًا أنّ المصفوفات تقوم بالعدّ بدءًا من 0 وليس 1. إذًا فباستخدامنا 2 فإنّنا قد قمنا بالبحث عن العنصر الثالث في المصفوفة. لمعرفة إذا كان المجال يحتوي على قيمة معيّنة أو لا يمكننا استخدام الدّالّة المنطقيّة ?include. numbers.include?(5) # true ستقوم روبي بإرجاع true حيث أنّ المجال (قمنا بإنشائه سابقًا في البداية) يحتوي بالفعل على القيمة 5. فأنت هنا تسأل روبي هل القيمة 5 موجودة في المجال numbers؟ لمعرفة إذا كان المجال الخاصّ بنا يتضمّن نهاية المجال مع القيم أم لا يمكننا فعل ذلك عن طريق دالّة ?exclude_end حيث تقوم بإرجاع true إذا لم يشتمل المجال على النّهاية وfalse إذا كان العكس. numbers.exclude_end? استخدامات المجالات تستخدم المجالات في كثير من الأحيان في المقارنة أو التكرار. مثال على المقارنة، التحقّق من وجود قيمة معيّنة في مجال محدّد من القيم. مثال على التكرار، تنفيذ حلقة Loop لفعل أمر ما 10 مرّات. يمكن إنشاء مجال باستخدام أيّ نوع من البيانات ولكن في أغلب الأحيان ستجد نفسك تستخدم المجالات من نوع السلاسل أو الأرقام فقط. السبب وراء ذلك هو قدرة روبي على ترتيب القيم في هذين النّوعين. فمثلاً، من السّهل إنشاء مجال 1 إلى 10، التحقّق من ما إذا كانت قيمة معيّنة موجودة في هذا المجال وأيضًا من السّهل طباعة كلّ رقم في المجال. الأمر ذاته مشابه مع السلاسل. تعرّفنا سابقًا أنّه بإمكاننا إنشاء مجال من الأرقام الصحيحة Integer من 0 إلى 10. الأمر الجيّد أيضًا أنّه بإمكاننا إنشاء مجالات من الأعداد العشريّة Float فمثلاً لو أردنا إنشاء مجال لنظام المعدّل التراكمي GPA فيمكننا إنشاؤه كالتّالي: gpa = 0.0..4.0 الآن إذا أردنا معرفة إذا كانت قيمة عشريّة معيّنة موجودة في هذا المجال أو لا (لنفرض مثلاً 2.5) فيمكننا فعل ذلك باستخدام دالّة ?include كالتّالي: gpa.include?(2.5) تطبيق عملي لا يبدو مثال المعدّل التراكمي السّابق مفيدًا كثيرًا، أليس كذلك؟ يمكننا جعله أكثر إفادة بتحديد مجال من 0 إلى 2 بحيث يكون هذا المجال هو مجال الإنذار كالتّالي: gpa_warning = 0.0..2.0 الآن لنطبّق ما تعلّمناه في درس العبارات الشرطيّة يمكننا إنشاء برنامج لاستقبال المعدّل التراكمي للطالب ومن ثمّ معالجة البيانات وطباعة معلومات عنها. افتح ملفًّا جديدًا واحفظه باسم gpa.rb أو أيّ اسم من اختيارك مع التأكّد من وجود rb. في نهاية اسم الملفّ. لنبدأ أوّلاً بطباعة التعليمات الخاصّة بالبرنامج، سنطلب من المستخدم إدخال المعدّل التراكمي الخاصّ به واستقبال المعدّل التراكمي كالتّالي: gpa_warning = 0.0...2.0 puts "Please Enter your GPA (0.0 to 4.0)" gpa_entry = gets.to_f في السّطر الأوّل قمنا بتعريف متغيّر باسم gpa_warning وقمنا بتعيين المجال 0 إلى 2 إليه، حيث هذا المجال هو مجال التنبيه لأيّ طالب حاصل على معدّل تراكمي بين 0 و2. بعد ذلك في السطر الثّاني طبعنا رسالة على الشّاشة تسأل المستخدم أن يدخل قيمة المعدّل التراكمي الخاصّ به بين 0 و 4. في السطر الثّالث أنشأنا متغيّر باسم gpa_entery وهو المتغيّر الذي ستقوم روبي بحفظ القيمة التي سيدخلها المستخدم إلى البرنامج به. أمر gets يتيح للمستخدم إدخال بيانات، دالّة to_f تستخدم لتحويل المُدخلات Inputs من سلاسل إلى أرقام عشريّة، حيث أنّ أيّ مدخل يتمّ اعتباره افتراضيًّا أنّه سلسلة (اسم الدّالّة نفسها هو اختصار لـ get string). قد تتساءل هنا، لماذا لم نضِف دالّة chomp إلى gets لحذف السطر الذي تضيفه روبي إلى المدخل عند الضغط على Enter؟ الإجابة هي أنّ السطر الزائد يتمّ حذفه بالفعل عند تحويل المُدخل إلى عدد عشري. الآن لدينا ما نحتاج للحصول على مُدخل من المستخدم. الجزء الثّاني من البرنامج هو أن نقوم بالتعامل مع هذه البيانات بحيث تقوم بطباعة شيء محدّد بناءً على ما يدخله المستخدم. if (gpa_entry < 0.0 || gpa_entry > 4.0) puts "False entery. Please enter a numberic value between 0 and 4." elsif (gpa_warning.include?(gpa_entry)) puts "Your GPA is too low! You need to do something about it." else puts "Congratulations! Your GPA is good. No warnings." end ماذا فعلنا هنا؟ أوّلاً، عبارة if الأولى تقوم بالتحقّق إذا كان ما أدخله المستخدم أصغر من 0 أو أكبر من 4 وهذه حالات غير متوقّعة في المعدّل التراكمي. إذا كان المُدخل يحقّق أحد الشرطين سيقوم البرنامج بإخبار المستخدم أنّ عليه إدخال رقم ما بين 0 و 4. عبارة elsif تتحقّق هل يحتوي المجال الموجود في المتغيّر gpa_warning على قيمة المتغيّر gpa_entery والذي هو القيمة التي أدخلها المستخدم. إذا تحقّق شرط العبارة فهذا يعني أن المعدّل التراكمي الذي تمّ إدخاله سيكون بين 0 و2 وفي هذه الحالّة سيقوم البرنامج بطباعة رسالة التنبيه للمستخدم. في حالة إذا كان المعدّل التراكمي غير ذلك، أي أنّه ليس أقل من 0 أو أكبر من 4. وأيضًا ليس بين 0 و2 فسيقوم البرنامج بإخبار المستخدم أنّ معدّله التراكمي جيّد وأنّه لا توجد أيّ تنبيهات له. الآن إذا قمت بتجربة البرنامج ستجده يعمل بشكلٍ جيّد ولكن ماذا يحدث عندما تُدخل سلسلة نصيّة؟ يقوم البرنامج بطباعة رسالة التنبيه بأنّ المعدّل التراكمي منخفض، أعلم أنّك لم تتوقّع ذلك. تقوم دالّة t_f بتحويل ما نستدعيها عليه إلى عدد عشري وإذا كان المُدخل هو نصّ عادي فتقوم بتحويل قيمته إلى 0.0 وهي القيمة الموجودة لدينا بالفعل في المجال. والآن حان دورك، هل يمكنك حلّ هذه المشكلة بحيث أنّه عند إدخال المستخدم أحرفًا وقيمًا ليست بالأرقام يطبع له البرنامج أنّ عليه إدخال أرقام؟ خاتمة تعرّفنا في هذا الدّرس والدّروس الماضية على أنواع المجموعات المختلفة في روبي مثل المصفوفات، جداول التّقطيع والمجالات. يمكنك قراءة توثيق روبي حول المجالات لمعرفة المزيد عنها. جرّب تحسين البرنامج الموجود بقسم التطبيق العملي بأن يقوم بطباعة بيانات أخرى حول المعدّل التراكمي بناءً على إدخال المستخدم وموقع هذا المعدّل بالنسبة للمجال المحدّد. إذا كنت تودّ إضافة معلومة عن المجالات أو واجهتك مشاكل أو لديك تساؤل حول الدّرس فلا تتردّد في السؤال بقسم التعليقات أدناه.
  3. جدول التّقطيع Hash هي بنية بيانات Data Structure مشابهة إلى حد كبير للمصفوفات التي تحدّثنا عنها في الدّرس السّابق (حتّى أنّ جداول التّقطيع تسمّى في بعض اللُّغات الأخرى Associative Arrays). يندرج الاثنان تحت ما يسمّى بالمجموعات Collections. يتيح لنا النوعان حفظ بيانات مختلفة مرّة واحدة دون الحاجة إلى استخدام الكثير من المتغيّرات لحفظها. إلا أنّ جداول التّقطيع تختلف عن المصفوفات بعض الشيء. فمثلاً يمكننا الإشارة إلى عنصر في المصفوفة عن طريق مكان هذا العنصر أو ما يسمّى بالدليل Index، أمّا بالنسبة لجدول التّقطيع فنستخدم معرّفًا Identifier للإشارة إلى العنصر الذي نريد الوصول إليه. يمكن اعتبار جداول التّقطيع على أنّها قوائم مكوّنة من أزواج مفاتيح Key وقيمة Value. يمكن للمعرّف أو المفتاح أن يكون أي نوع من أنواع بيانات روبي التي تعرّفنا عليها في الدروس السّابقة. ولكن أكثر الأنواع المستخدمة شيوعًا هو السلاسل، الأرقام و الرموز Symbols (هذا الأخير هو أكثرها شيوعًا على الإطلاق). سنتعرّف في هذا الدّرس على كيفيّة إنشاء والتّعامل مع جداول التّقطيع. إنشاء جدول التقطيع لنبدأ العمل مع جداول التّقطيع الآن، ابدأ جلسة روبي جديدة في سطر أوامر روبي التفاعليّ عن طريق كتابة أمر irb في الطرفيّة. عمليّة إنشاء جدول التّقطيع تشبه نوعًا ما عمليّة إنشاء مصفوفة. هناك طرق مختلفة لإنشاء جدول تقطيع. يمكن تهيئة Instantiate جدول تقطيع باستخدام الحاضنات Curly Braces أو تهيئة نسخة من صنف Hash. لنتعرّف أوّلاً على الطريقة الأولى. وهي عبارة عن إنشاء جدول تقطيع فارغ ومن ثمّ إضافة عناصر إليه فيما بعد. فمثلاً إذا أردنا إنشاء جدول تقطيع فارغ وتعيينه إلى متغيّر اسمه myHash نفعل ذلك كالتّالي: myHash = Hash.new تأكّد من كتابة Hash بحرف كبير. هناك طريقة أقصر من ذلك أيضًا وذلك بتعيين حاضنات فارغة للمتغيّر هكذا: myHash = {} بعد الضغط على Enter في الحالتين ستجد أن روبي قد قامت بإرجاع حاضنات فارغة معلنةً عن إنشاء جدول تقطيع فارغ. ولكن ماذا سنفعل بجدول تقطيع فارغ على كل حال؟ جدول تقطيع فارغ ليس بالشيء المفيد على الإطلاق. الآن لو أردنا إنشاء جدول تقطيع باستخدام الحاضنات وتعيينه إلى متغيّر اسمه marge ثم بداخل جدول التّقطيع قمنا بإضافة العناصر المتكوّنة من مفتاح وقيمة. نفعل ذلك هكذا: marge = { :name => "Marge Simpson" } ماذا فعلنا هنا؟ أنشأنا متغيّرًا باسم marge وقمنا بتعيين قيمة جدول التّقطيع الذي أنشأناها في الطرف الأيمن لذلك المتغيّر. وضعنا بجدول التّقطيع عنصرًا واحدًا مكوّنًا من المفتاح name: والذي هو من نوع Symbol (عرّفنا النّوع عن طريق النقطتين Colon الموجودتان قبله) والقيمة التي هي عبارة عن سلسلة، قمنا بتعيين القيمة إلى المفتاح عن طريقة ما يسمّى بسهم جدول التّقطيع Hash Rocket (<=). يعدّ استخدام الرموز (ٍSymbol) كمفاتيح في جداول التّقطيع مثلما فعلنا في المثال السّابق أمرًا شائعًا جدًا في روبي. قد تتساءل عن السبب؟ السبب الرئيسي هو أنّ الرموز تستخدم الذّاكرة بطريقة أفضل وأكثر إفادة بكثير من السلاسل مثلاً. هناك طريقة أخرى مختصرة لإنشاء جداول التّقطيع ولتوضيح الطريقة سنقوم بإنشاء جدول تقطيع جديد ونعيّنه إلى المتغيّر homer كالتّالي: homer = { name: "Homer Simpson" } هل لاحظت الفرق بين هذه الطّريقة والسّابقة؟ لا تختلف هذه الطريقة كثيرًا عن السّابقة، فقط حذفنا سهم جدول التّقطيع ونقلنا النقطتين لتصبحا بين المفتاح والقيمة. لا زال المفتاح رمزًا كما هو لم يتغيّر نوعه. لاحظ عند الضّغط على Enter ستقوم روبي بإرجاع جدول تقطيع بالصورة الافتراضيّة لها (باستخدام سهم جدول التّقطيع ) رغم استخدامنا للطريقة المختصرة، كالتّالي: {:name => "Homer Simpson"} يمكننا إنشاء جدول تقطيع يحتوي على أكثر من زوج مفتاح/قيمة. مثلاً لنعد إنشاء جدول التّقطيع homer من جديد هكذا: homer = { name: "Homer Simpson", job: "Nuclear Safety Inspector", children: ["Bart", "Lisa", "Maggie"] } كما تلاحظ يمكننا استخدام أنواع مختلفة من الكائنات كعناصر في جدول التّقطيع . لسنا مضطرّين لاستخدام السلاسل فقط. فدلينا في المثال السّابق قيم العنصرين name و job من نوع سلسلة والعنصر الثالث الذي يحتوي على مفتاح children قيمته من نوع مصفوفة مكوّنة من ثلاثة عناصر. التعامل مع جداول التقطيع إذا أردنا التحقّق إذا كان هناك مفتاح معيّن موجود في جدول التّقطيع أم لا يمكننا فعل ذلك باستخدام دالّة include. فمثلاً إذا أردنا معرفة إذا كان لدى homer وظيفة يمكننا التحقّق كالتّالي: homer.include?(:job) إذًا فقد استخدمنا اسم جدول التّقطيع أو المتغيّر الذي قمنا بتعيين جدول تقطيع له، ثم لدينا استدعاء دالّة include، وحيث كما ذكرنا في الدروس السّابقة أنّ include دالّة منطقيّة Boolean Method والدوال المنطقيّة تنتهي بعلامة استفهام لأن ناتج استدعائها true أو false (باختصار هي كأن تسأل مثلاً، هل لهومر وظيفة؟ لن تجد إطلاقًا إجابة غير نعم أو لا). إذًا ناتج هذا الأمر السّابق سيكون true إذا وجدت روبي قيمة للمفتاح job أو false إذا لم تجد. وبالنّظر إلى جدول التّقطيع التي لدينا فنتوقّع إجابة روبي بـ true حيث أنّه موجود وظيفة (المفتاح job) لـ homer بالفعل في جدول التّقطيع . إذًا نحن نعرف أنّ العنصر موجود، الآن نريد معرفة كيف يمكننا استخدام هذه القيمة (سواء لطباعتها على الشّاشة أو لو استخدامها في عمليّات أخرى). للوصول إلى القيمة الفعليّة بدلاً من التحقّق من وجودها فقط ولمعرفة أن هذه القيمة خاصّة بالمفتاح المحدّد كل ما نفعله هو استخدام المفتاح بطريقة مشابهة جدًا لتلك التي استخدمناها مع الدليل Index في المصفوفات. إذًا إذا أردنا معرفة وظيفة homer يمكننا فعل ذلك كالتّالي: homer[:job] إذًا كلّ ما فعلناه أعلاه هو كتابة اسم جدول التّقطيع واسم المفتاح بين قوسين مربّعين. بعد تنفيذ الأمر سترجع لك روبي الوظيفة. لكن ماذا لو استدعينا مفتاحًا ليس موجودًا في جدول التّقطيع أصلاً؟ مثلاً لو أردنا معرفة عمر homer باستخدام مفتاح age:. لم نقم بحفظ قيمة كهذه في جدول التّقطيع لذلك إذا استدعيناها فلن ترجع روبي شيئًا غير nil. ولكن ماذا تعني nil؟ nil هو كائن في روبي يمثّل اللاشيء إذا أردت تعريفه كذلك. متى أخفقت دالّة بإرجاع قيمة مفيدة أو ذات معنى فإنّها تقوم بإرجاع nil. إذا أردنا معرفة عدد القيم الموجودة في جدول تقطيع يمكننا استخدام دالّة length. جرّب تنفيذ الأمر التالي وستحصل على طول جدول التّقطيع الخاصّة بك: homer.length قد تحتاج إلى إضافة قيم جديدة إلى جدول التّقطيع (فارغة كانت أو تحتوي على عناصر) بعد إنشائها، يمكنك فعل ذلك عن طريقة كتابة اسم المفتاح الجديد وجعله مساويًا للقيمة التي تريد تعيينها إلى ذلك المفتاح. فمثلاً إذا أردنا إضافة مفتاح age إلى homer والذي أخبرتنا روبي أعلاه بأنّه ليس موجودًا في جدول التّقطيع عن طريقة إرجاعها nil. فيمكننا فعل ذلك كالتّالي: homer[:age] = 38 الآن للتأكّد من أن العنصر قد تمّت إضافته فإنّ كلّ ما علينا فعله هو كتابة اسم جدول التّقطيع (homer في هذه الحالة) والضغط على Enter. ستجد أنّ المفتاح age وقيمته موجودين بنهاية جدول التّقطيع . والآن أيضًا يمكنك سؤال روبي عن قيمة المفتاح age وتوقّع ظهور قيمة بدلاً من اللاقيمة nil. يمكن أيضًا إضافة جدول تقطيع ليكون أحد القيم في جدول تقطيع آخر. مثلاً إذا أردنا إضافة بيانات زوجة homer إلى جدول التّقطيع الخاصّ به ولدينا فعلاً جدول تقطيع باسم زوجته marge فيمكننا فعل ذلك كالتّالي: homer[:wife] = marge ماذا حدث؟ قمنا هنا بتعيين جدول التّقطيع الموجودة بالمتغيّر marge إلى المفتاح الجديد wife المضاف إلى جدول التّقطيع homer. بعد كتابة هذا والضّغط على Enter ستجد أنّ روبي قد أعادت القيمة الموجودة في marge وهي جدول تقطيع مكوّنة من عنصر واحد. {:name => "Marge Simpson"} هل توقّعت أن يكون الأمر أكثر صعوبة؟ لا تتوقع أن تواجه صعوبة في روبي لحسن الحظّ. الآن إذا أردنا النظر في جدول تقطيع homer ستجد أنّ جدول التّقطيع قد أضيف. ما فعلناه هنا هو أنّنا قمنا بإنشاء جدول تقطيع متداخل Nested Hash، بمعنى أنّ لدينا جدول تقطيع داخل جدول تقطيع آخر. الآن إذا أردنا الوصول إلى قيمة جدول تقطيع المتداخل نفعل ذلك عن طريق استدعاء كل مفتاح بالترتيب بدءًا من جدول التّقطيع المحتوي على الآخر. فمثلاً إذا أردت معرفة اسم زوجة هومر فنستدعي المفتاح wife كما تعوّدنا ولكن نضيف إلى ذلك المفتاح أيضًا مفتاح name الموجود في جدول تقطيع marge كالتّالي: homer[:wife][:name] إذًا فالمفتاح الأوّل هو الموجود بجدول تقطيع homer والمفتاح الثّاني هو الموجود في جدول تقطيع marge. بالضغط على Enter ستقوم روبي بإرجاع القيمة الموجودة في المفتاح name الموجود في marge وليس homer، لا تنس ذلك. "Marge Simpson" دوال جداول التقطيع الكثير من الدوال الخاصّة بجداول التّقطيع هي نفسها الخاصّة بالمصفوفات تعرّفنا على اثنين منها (include و length). لحذف عنصر في جدول تقطيع نستخدم دالّة delete والتي تستقبل مفتاح العنصر المراد حذف كمعطى. تقوم الدّالة أيضًا بإرجاع القيمة التي تمّ حذفها. homer.delete(:age) # 38 لحذف أوّل عنصر في جدول تقطيع نستخدم دالّة shift والتي تحذف أوّل زوج مفتاح/قيمة بجدول تقطيع وتقوم بإرجاعهما في مصفوفة. homer.shift # [:name, "Homer Simpson"] الدوال الخاصة بجداول التقطيع فقط رغم ذكرنا سابقًا أنّ دوال جداول التّقطيع تشبه دوال المصفوفات إلا أن جداول التّقطيع تختصّ ببعض الدوال عن المصفوفات نظرًا لاحتوائها على مفاتيح وقيم. فمثلاً دالّة keys تقوم بإرجاع مصفوفة بها جميع المفاتيح الموجودة بجدول تقطيع . homer.keys # [:job, :children, :wife] دالّة values تقوم بإرجاع مصفوفة تحتوي على جميع القيم الموجودة في جدول تقطيع . homer.values # ["Nuclear Safety Inspector", ["Bart", "Lisa", "Maggie"], { :name => "Marge Simpson" }] لمعرفة إذا كانت قيمة معيّنة موجودة في جدول تقطيع يمكننا استخدام دالّة ?has_value أو اختصارها ?value. homer.value?("Homer Simpson") # false قد تتساءل لماذا قامت روبي بإرجاع false رغم إنشائنا للمفتاح في البداية؟ دعني أُذكّرك أنّه قد تمّ حذف العنصر باستخدام دالّة shift أعلاه. لمعرفة إذا كان مفتاح معيّن موجود في جدول تقطيع أم لا يمكننا استخدام دالّة ?has_key أو اختصارها ?key. homer.key?(:job) # true خاتمة تعرّفنا في هذا الدّرس على جداول التّقطيع، كيفيّة إنشائها وكيفيّة التعامل معها وإضافة عناصر إليها وبعض الدوال الخاصّة بها. حان دورك للتطبيق على ما تعلّمت. يمكنك معرفة المزيد عن جداول التّقطيع عن طريق قراءة توثيق روبي. ربما تريد الآن تحسين قائمة المشتريات (التي استخدمناها كمصفوفة في الدّرس السّابق) عن طريق وضعها في جدول تقطيع بدلاً من مصفوفة. إذا استعصى عليك أمر أو لديك سؤال لا تتردّد في طرحه في قسم التعليقات أدناه.
  4. بعض أنواع البيانات التي تحدّثنا عنها في الدروس السّابقة هي السلاسل و الأرقام. تتيح لنا السلاسل إمكانيّة التعامل مع النصوص الخاصّة ببرنامجنا والأرقام تمكننا من التعامل مع البيانات الرقميّة. لنفترض مثلاً أنّنا نريد إنشاء قائمة مشتريات، بداخل تلك القائمة لدينا أسماء المشتريات. يمكننا إنشاء تلك القائمة على شكل سلسلة String مفصول بين كل عنصر فيها بفاصلة. أو يمكننا استخدام ثلاثة سلاسل محفوظة بمتغيّرات مسمّاة item1, item2 وهكذا. ولكن لحسن الحظّ فإنّ روبي تُوفّر لنا نوعًا يمكنه التعامل مع هذا النّوع من البيانات فعلاً يسمّى بالمصفوفة Array. المصفوفة هي عبارة عن حاوية للبيانات. تُستخدم المصفوفات لتخزين أنواع مختلفة من البيانات مثل السلاسل، الأرقام وأيّ نوع آخر من كائنات روبي. سنتعرّف في هذا الدّرس على كيفيّة إنشاء المصفوفات والتّعامل معها في روبي. إنشاء مصفوفة سنستخدم سطر أوامر روبي التفاعليّ الآن للتعرّف على المصفوفات. ابدأ جلسة روبي في الطرفيّة عن طريق كتابة irb والضّغط على Enter. يمكن إنشاء مصفوفة حرفيّة Array Literal عن طريق وضع الكائنات داخل أقواس مربّعة Square Brackets مفصول بينها بفاصلة. كالمثال أدناه، أنشأنا قائمة من الأعداد الأوّليّة: [2, 3, 5, 7] لا تشترط المصفوفات بأن تقوم بتخزين أرقام فقط بها. يمكنك أيضًا إنشاء مصفوفة مكوّنة من سلاسل هكذا: ["apples", "oranges"] هناك أيضًا طريقة أقصر لإنشاء مصفوفة من السلاسل. نبدأ ذلك بكتابة علامة النّسبة المئويّة متبوعة بحرف w ثمّ بعد ذلك يمكنك الاختيار إذا كنت تريد استخدام الأقواس Parentheses أو الحاضنات Curly Brackets لبدء المصفوفة، الأمر الإيجابي حول هذه الطريقة هو أنّه باستخدامها لن تصبح في حاجة إلى وضع كل سلسلة بين علامات اقتباس وأيضًا لن تحتاج إلى الفصل بين عناصر المصفوفة باستخدام الفاصلة، استخدام المسافات يفي بالغرض. %w(apples, oranges) %w{apples oranges} عند كتابة المصفوفة بأحد الطريقتين أعلاه والضّغط على Enter ستلاحظ أنّ روبي ستضعها في الصّورة الافتراضيّة للمصفوفة، أقواس مربّعة ومفصول بين السلاسل بفاصلة. ليس مفروضًا عليك استخدام كائنات من نوع بيانات واحد في المصفوفة فيمكنك إنشاء مصفوفة تحتوي على أكثر من نوع من العناصر، كما تلاحظ في المثال أدناه فقد أنشأنا مصفوفة تحتوي على عدد صحيح Integer، سلسلة وعدد عشري Float: [1, "two", 3.0] هناك طريقة أخرى لإنشاء مصفوفة وذلك باستخدام دالّة new كالتالي: fruits = Array.new ما فعلناه هنا هو إنشاء متغيّر باسم fruits وتعيين مصفوفة جديدة فارغة إلى ذلك المتغيّر باستخدام دالّة new. قد تتساءل، إذا كان بالإمكان تعيين مصفوفة إلى متغيّر فهل يمكن استخدام متغيّر كعنصر في مصفوفة؟ نعم يمكن ذلك ويكون نوع العنصر هو نوع البيانات الموجودة في المتغيّر، جرّب إنشاء متغيّر ثم ضعه في المصفوفة كعنصر كما فعلت سابقًا مع السلاسل، تسمّى هذه العمليّة بالاستيفاء Code Interpolation. item = "apples" fruits = %W(#{item} oranges) لاحظ أنّنا استخدمنا حرف W كبير بدلاً من الصّغير الذي استخدمناه سابقًا. المصفوفات متعددة الأبعاد يمكنك إنشاء مصفوفة تحتوي على مصفوفات أخرى بداخلها، تسمّى بالمصفوفة متعدّدة الأبعاد Multidimensional Array. يعد هذا النوع من المصفوفات مفيدًا لإنشاء مستوى إحداثيّات. يمكن إنشاء مصفوفة متعدّدة الأبعاد هكذا: [[1, 3], [5, 7]] الوصول إلى عنصر أو عدة عناصر بالمصفوفة تعدّ المصفوفات أحد أدوات روبي المهمّة. وتمتلك المصفوفات بعض الدوال المفيدة للوصول إلى عنصر معيّن بها. للتعرف على بعض تلك الدوال سنقوم بإنشاء مصفوفة بقائمة المشتريات تحتوي على 5 عناصر. لنقم بإنشاء متغيّر باسم list وتعيين المصفوفة التي نريد إلى ذلك المتغيّر. list = %w(apples oranges milk bread sugar) للوصول إلى قيمة معيّنة في المصفوفة نكتب مكان وجود هذه القيمة في أقواس مربّعة، مكان تواجد القيمة يسمّى دليل index. إذًا إذا أردت أن أجد العنصر الموجود في المكان الأوّل من المصفوفة نكتب اسم المصفوفة، الأقواس المربّعة ورقم الدليل بداخلها هكذا: list[1] ولكن ماذا أعادت لنا روبي عند تنفيذ هذا؟ أعرف أنّك لم تتوقّع أن تعيد orangesبدلاً من apple. لماذا حدث ذلك لأنّ الترقيم في المصفوفات يبدأ من 0 وليس 1 فإذا أردنا الوصول إلى أوّل عنصر على الإطلاق في المصفوفة نكتب ذلك كالتالي: list[0] القيم السالبة يستخدم نظام الترقيم الخاص بالمصفوفات قيمًا سالبة أيضًا وذلك إذا أردنا بدء العدّ من آخر المصفوفة. إذًا إذا أردت الوصول إلى آخر عنصر في المصفوفة يمكنك استخدام -1. list[-1] هناك أيضًا دوال مدمجة جاهزة للوصول إلى أوّل وآخر عنصر في المصفوفة. list.first list.last دالة fetch يمكن استخدام دالّة fetch مع الدليل لإرجاع قيمة العنصر الموجود بهذا الدليل. list.fetch(2) # "milk" إذا تم كتابة معطى ثاني في الدّالّة ولا يوجد هناك العنصر الذي يشير إليه الدليل المحدّد فسيتمّ إرجاع القيمة الموجودة في المعطى الثّاني كقيمة افتراضيّة. مثال: list.fetch(20, "Not found") # "Not found" المصفوفة الجزئية يمكننا أيضًا إرجاع مصفوفة جزئيّة Subset Array من مصفوفة عن طريق كتابة معطى Parameter إضافي مع الدليل. يشير هذا المعطى إلى طول المصفوفة الجزئيّة التي نريد إرجاعها. إذًا إذا أردنا إرجاع أوّل ثلاثة عناصر في المصفوفة نكتب ذلك كالتالي: list[0, 3] # ["apples", "oranges", "milk"] طريقة أخرى لإرجاع مصفوفة جزئيّة هو استخدام مجال معيّن range. list[0..2] # ["apples", "oranges", "milk"] دالة include لمعرفة إذا كانت مصفوفة تحتوي على كائن معيّن نستخدم دالّة include والتي تستقبل معطى باسم الكائن الذي نريد التحقّق من وجوده. وحيث أنّ الدّالّة منطقية (بمعنى أنّها ترجع true أو false فقط) فإنّنا نكتب في نهايتها علامة استفهام، ?include. إذًا لو أردنا معرفة إذا كانت تحتوي مصفوفة list على سلسلة apples نكتب ذلك كالتالي: list.include?("apples") معرفة عدد عناصر المصفوفة إذا أردت معرفة كم عدد العناصر بالمصفوفة فيمكن استخدام دالّة size والتي تقوم بإرجاع عددًا صحيحًا يمثّل عدد العناصر الموجودة بالمصفوفة. list.size اسم آخر لدالّة size هو length. جرّب كتابة الأمر التالي ولاحظ كيف تمّ إرجاع نفس النتائج. list.length إضافة عناصر إلى المصفوفة دالة push ماذا لو أردنا إضافة شيء إلى المصفوفة؟ يمكننا إضافة سلسلة تحتوي على "cheese" إلى نهاية المصفوفة باستخدام دالّة push. تقوم الدّالّة بإلحاق السلسلة التي نريد إضافتها بنهاية المصفوفة. list.push("cheese") هناك عامل اختصار Shorthand Operator لفعل نفس الوظيفة وهي أقواس الزاوية المزدوجة Double Angle Brackets (<<). فمثلاً إذا أردنا إضافة سلسلة "juice" إلى مصفوفة list بطريقة أسرع نكتب ذلك هكذا: list << "juice" أسهل وأسرع بكثير من دالّة push أليس كذلك؟ والأمر اللّطيف أيضًا حول ذلك أن هذه الأسهم تشير إلى مصفوفة list كما لو كانت تخبر روبي بإضافة السلسلة إلى تلك المصفوفة. طريقة أخرى لإضافة عناصر إلى آخر المصفوفة هو استخدام معامل =+ والذي يعني أن تجعل المصفوفة تساوي نفسها (=) بالإضافة إلى (+) القيمة الموجودة في الطرف الأيمن. list += ["bananas", "cereals"] الشيفرة البرمجيّة أعلاه تطلب من روبي بأن تضيف السلسلتين "bananas" و"cereals" إلى نهاية المصفوفة list. دالة unshift إذا أردنا إضافة عنصر إلى بداية المصفوفة وليس نهايتها فيمكننا استخدام دالّة unshift والتي تعمل عمل push مع فرق أنّها تضيف العنصر إلى بداية المصفوفة. list.unshift("carrots") حذف عناصر من المصفوفة دالة pop يمكننا استخراج آخر عنصر من المصفوفة باستخدام دالّة pop. لنقل مثلاً أنّني قد غيّرت رأيي ولا أريد شراء العصير. يمكن إخراج العصير وهو العنصر الأخير في المصفوفة هكذا: list.pop كما تلاحظ لا نحتاج إلى معطيات لهذه الدّالّة فهي تقوم آليًّا بإخراج العنصر الأخير في المصفوفة. بعد تنفيذ الأمر في سطر أوامر روبي التفاعليّ ستلاحظ أنّ روبي قامت بإرجاع قيمة العنصر المحذوف ولم ترجع المصفوفة نفسها. هذه الميزة مفيدة إذا أردنا استخدام العنصر الأخير/المحذوف. لكن لا تستخدم هذه الدّالّة للوصول إلى آخر عنصر إذا لم تكن تريد حذفه فعلاً حيث أنّك لو تحقّقت من المصفوفة من جديد ستجد أنّ العنصر الأخير قد اختفى. دالة shift دالّة shift مشابهة لدالّة unshift والتي تضيف عنصر إلى بداية الدّالّة، الفرق الوحيد هو أنّ دالّة shift تقوم بإرجاع وحذف العنصر الأوّل من المصفوفة. أو بعبارة أخرى، هي تقوم بنفس عمل دالّة pop لكن على بداية المصفوفة. list.shift دالة drop يمكننا استخدام دالّة drop لحذف عدد من العناصر من مصفوفة معًا. المعطى الخاصّ بالدّالّة هو عدد العناصر المطلوب حذفها من بداية الدّالّة. list.drop(2) # تقوم بحذف عنصرين من بداية الدّالّة دالة !slice قد تتساءل ماذا لو أردت حذف عناصر ليست في بداية أو نهاية المصفوفة. يمكننا في هذه الحالة استخدام دالّة !slice. تأخذ دالّة !slice المعطى الأول هو رقم الدليل المطلوب البدء منها والمعطى الثّاني هو عدد العناصر المطلوب حذفها. list.slice!(0, 3) لاحظ أنّه في حال ما إذا لم نضف علامة التّعجّب في نهاية اسم الدّالة فإننا سنحصل على جزء من المصفوفة مثلما هو مُتوقّع، لكنّه لن يتم حذف العناصر من المصفوفة الأصلية دالة sort يمكننا ترتيب مصفوفة باستخدام دالّة sort. الأمر التالي سيؤدّي إلى ترتيب المصفوفة استنادًا إلى الحروف الأبجديّة: list.sort ستلاحظ أنّه تمّ إرجاع المصفوفة وعناصرها مرتّبة أبجديًّا. ولكن لم يغيّر ذلك شيئًا في ترتيب المصفوفة الأصلي، يمكنك التحقّق من ذلك بنفسك. فقط اكتب اسم المصفوفة واضغط Enter. ستجد أنّ المصفوفة الأصليّة لم تتغيّر. ولكن إذا أردت ترتيب المصفوفة وتغيير المصفوفة الأصليّة ماذا نفعل؟ يمكننا الآن الرجوع إلى دوال Bang التي تحدّثنا عنها في درس السلاسل والتي تقوم بتعديل القيمة الأصليّة للكائن ونستدعيها عن طريقة كتابة اسم الدالّة الأصليّة متبوعة بعلامة تعجّب. list.sort! دالة reverse يمكننا استخدام دالّة reverse من أجل طباعة المصفوفة معكوسة. هذه المصفوفة أيضًا لا تغيّر من قيمة المصفوفة الأصليّة للأبد، ولكن إن أردنا تغيير المصفوفة الأصليّة فلدينا دالّة reverse!. list.reverse دالة join دالّة أخيرة سنتعرّف عليها هي دالّة join. هذه الدّالّة مفيدة جدًّا لأنّه يمكن استخدامها لإنشاء سلسلة تقوم بدمج جميع عناصر مصفوفة معًا. تستقبل الدّالّة معطى يحتوي على الرّمز الذي تريد استخدامه كفاصل. مثلاً الأمر التالي: list.join(",") ماذا فعلنا هنا؟ لقد استدعينا دالّة join على مصفوفة list ومعطى الدّالّة هو سلسلة تحتوي على فاصلة والتي ستستخدم كفاصل بين عناصر المصفوفة. عند تنفيذ هذا الأمر ستطبع لك روبي على الشّاشة سلسلة تحتوي على جميع العناصر وبين كل عنصر والآخر الفاصلة التي أردنا استخدامها. خاتمة تعرّفنا في هذا الدّرس على أحد المفاهيم المهمّة في روبي وأيّ لغة برمجة عمومًا وهي المصفوفات. مع تعمّقك أكثر في تعلّم روبي ستلاحظ فوائد استخدام المصفوفات في شيفراتك البرمجيّة. تعرّفنا على الدوال الرئيسيّة المستخدمة مع المصفوفات ولكن إذا أردت معرفة معلومات أكثر عن ذلك يمكنك قراءة التوثيق الخاص بالمصفوفات في روبي.
  5. أطلقتُ مدوّنة ووردبريس منذ عامين. أضفت إليها الكثير من المحتوى لبضعة أشهر. كتبتُ المقال بعد المقال، مع التركيز على أن يكون المحتوى عالي الجودة. كل هذا أملاً في أن يأتي النجاح ولو بعد حين. ولكن كما هي العادة في هذه القصص، بعد فترة صرفتني التزامات أخرى عن المدوّنة، وتركتها في حالة من الإهمال. لم أنشر حتى كتابة هذه السطور مقالاً واحدًا على الموقع لمدّة تزيد عن 15 شهرًا. كانت المدوّنة تجذب أقل من 2000 زائرًا شهريًا وقت التخلّي عنها. قررتُ قبل بضعة أيّام التحقّق من إحصاءات الموقع على تحليلات جوجل للمرّة الأولى خلال مدّة تزيد عن العام. والعجيب أنّي اكتشفت أنّ المدوّنة قد جذبت أكثر من 10,000 زائرًا في الشهر السابق من دون أيّ تدخل من طرفي. ربّما تقول أنّها أيّام سعدي ولكن كانت هناك مشكلة كبيرة: المقاييس. نتحدّث بالتحديد عن معدّل ارتداد (Bounce Rate) تجاوز 90%، فقط 1.18 صفحة في الجلسة الواحدة ومتوسّط الجلسة 46 ثانية. إذًا ما هو المغزى من القصّة؟ ببساطة لا يهم عدد الزّيارات الذي تحصل عليه، فإنّ موقعك لن يربح شيئًا إذا لم يكن مُحسّنًا بشكلٍ يتوافق مع قابلية الاستخدام. يعتبر الحصول على زوّار لموقع هو نصف التحدّي، ما يهمّ حقًّا هو جعل هؤلاء الزوّار يسجّلون في موقعك. ومن تجربتي فإنّ قابلية الاستخدام غالبًا ما تكون الجانب الذي تُهمله الكثير من المُدوّنات والمشاريع التقنية على الويب. لحسن الحظّ فإنّ ووردبريس (وعدد لا يحصى من القوالب والإضافات) يعطينا كل الأدوات التي نحتاجها لبناء مواقع قابليّة استخدامها عالية. في هذا المقال سنقوم باستكشاف خمسة طرق رئيسيّة والتي من خلالها يمكنك جعل تجربة تصفّح موقع ووردبريس الخاص بك ممتعة أكثر. لماذا يعد "تحسين تجربة المستخدم" سببا في غاية الأهمية لنجاح موقعك/ مدوّنتك ربّما لا حاجة لي أن أذكّرك بماهية تجربة المستخدم (User Experience – UX) ولكن إذا كنت ترغب في معرفة المزيد، فلدينا قسم يحتوي مجموعة مقالات حول تجربة المستخدم على أكاديمية حسوب. كما هو مُتوقّع فإن تحسين تجربة المستخدم (User Experience Optimization – UXO) تهدف إلى تحسين موقعك ليكون أكثر قابلية للاستخدام. لاحظ أنّنا هنا لا نتحدّث عن جانب تصميم الموقع في حدّ ذاته. فيمكن لموقع سيء التصميم أن يقدّم تجربة مستخدم رائعة لجمهوره المستهدف. إنّما نتحدّث هنا تحديدًا عن "قابلية استخدام" موقعك. يرتبط هذا الأمر ارتباطًا وثيقًا بالتصميم الخاص بموقعك ولكن لا يعتمد بالضرورة على جودة التصميم في حدّ ذاتها. لن نتطرّق اليوم لكيفيّة جعل موقعك يبدو جميلًا وإنّما سنتطرّق إلى كيف تجعل موقعك قابلاً للاستخدام على أكمل وجه. الأمر الذي يهم في نهاية المطاف إذا أردت الحصول على عدد أكبر من الزوّار الدائمين. 1- التصميم المتجاوب (Responsive Design) من المؤكّد أنّك تعرف مدى أهميّة التصميم المتجاوب. إلا أنّه هناك اختلافًا كبيرًا بين معرفة أهميّة التصميم المتجاوب وأن يكون لديك بالفعل تصميم ووردبريس متجاوب وقابل للاستخدام بشكلٍ عالي الجودة. الأمر بسيط: إذا كان موقعك غير قابل للاستخدام على أكبر عدد من الأجهزة المستخدمة بواسطة جمهورك المستهدف، فإنّ موقعك لا يعدّ متجاوبًا بما فيه الكفاية. لأن هذه هي الفكرة عندما يتعلّق الأمر بالتجاوب. موقعك ليس إما مُتجاوبًا أو ليس مُتجاوب فالإجابة على هذا السؤال (هل موقعك مُتجاوب) ليست “نعم” أو “لا” بل هي نسبة مئوية إن صحّ التّعبير، حيث يجب أن نجيب على سؤال آخر وهو "ما نسبة الزيارات التي يظهر فيها موقعك مُتجاوبًا". يمكنك معرفة أكثر الأجهزة التي يستخدمها زوّار موقعك من خلال تحليلات جوجل عن طريق مسار Audience > Mobile > Devices: في المثال أعلاه يمكنك رؤية أنّ غالبيّة زوّار الموقع يستخدمون أجهزة Apple iPhone وiPad. ثاني أكثر الأجهزة شيوعًا لدى زوّار الموقع هو Nexus 5. بناءً على هذه البيانات فمن الطبيعي أن تقوم باختبار موقعك على iPhone وiPad. لن أخوض في تفاصيل اختبار قابلية الاستخدام لأجهزة الهاتف. بدلاً من ذلك فسنركّز على الإجابة على السؤال البديهي: هل تصفّح موقعك يبدو سهلاً على الهاتف الذي قمت باختياره؟ سيكون من الجيّد إذا استطعت طلب مساعدة من قريب أو صديق لك في هذا الاختبار (خاصّةً إذا لم ير هذا الشخص موقعك من قبل). إذا كنت تملك الجهاز المستخدم بصورة أكبر لتصفّح موقعك فبالتأكيد يمكنك اختبار موقعك عن طريق هذا الجهاز. ولكن إذا لم يكن لديك الجهاز فأقترح عليك أدوات اختبار مثل MobileTest.me وأداة StudioPress' responsive testing. هذه الخدمة رائعة أيضًا. نقطة أخيرة: إذا لم تكن لديك الوسائل الكاملة للحصول على تصميم متجاوب لموقع ووردبريس الخاص بك فبإمكانك استخدام Jetpack's Mobile Theme. هذا القالب ليس الحل الأمثل، ولكنّه مجّاني وفوري التنفيذ. 2- الانتقال الثابت (Fixed Navigation) يمكنك تخمين ما تقوم به هذه الخاصيّة من اسمها: يبقى شريط القوائم ثابتًا في الجزء العلوي من الشاشة عندما تقوم بالتمرير (Scroll)، بدل اختفائه. تزيد خاصيّة الانتقال الثابت من قابليّة استخدام موقعك حيث أنّها تعتبر بمثابة ضمان لإمكانيّة وصول الزوّار لأكثر الروابط أهميّة في موقعك أغلب الوقت. نظرًا لحجم شاشات الهواتف، فيجب عليك إذا كنت تستخدم خاصيّة الانتقال الثابت أن تتأكّد من أن شريط الانتقال لا يستولي على معظم مساحة الشاشة بالنسبة للهواتف ذات الشاشات الصغيرة. راجع قسم التصميم المتجاوب أعلاه لمعرفة الأدوات التي يمكنك اختبار تصميم موقعك من خلالها على أجهزة الهاتف للتأكد من شريط الانتقال يعمل بالشكل المطلوب. إذًا كيف يمكنك إضافة شريط الانتقال الثابت إلى موقعك؟ هناك عدّة حلول. هناك الكثير من قوالب ووردبريس التي تقدّم لك إمكانيّة الحصول على شريط انتقال ثابت كأمر أساسي لكن لا تبدو فكرة استبدال قالب بآخر لمجرد الحصول على هذه الخاصّيّة فكرة عملية. لحسن الحظ فإن هناك إضافات ووردبريس مجّانية جاهزة لحلّ هذه المشكلة ، لديك حرية الاختيار من بين ثلاث إضافات مجّانيّة عالية الجودة متاحة للتحميل: Sticky Header myStickymenu Sticky Menu (or Anything!) on Scroll 3- قائمة جانبية ثابتة (عناصر) بعد استعراض الانتقال الثابت يمكنك بسهولة تخمين ما تفعله القائمة الجانبيّة الثابتة. برأيي فإنّ هذه الميزة لها تأثير أقلّ من قائمة الانتقال الثابتة من ناحية قابليّة الاستخدام إلا أنّها تعتبر مفيدة إذا أردت على سبيل المثال جذب الانتباه إلى عنصر محدّد مهم في موقعك. لاحظ أنّني قد قمت بتضمين كلمة "عناصر" أعلاه لسبب وجيه – ستكون الخاصيّة أكثر فعاليّة إذا أردت تثبيت عنصر محدّد من الشريط الجانبي بدلاً من الشريط بأكمله. بإمكانك تثبيت القائمة الجانبية باستخدام: الإضافة المذكورة سابقًا Sticky Menu أو وودجت Q2W3 Widget - Sticky Widget: 4- أزرار المشاركة الاجتماعية العائمة (Floating Social Share Buttons) من المؤكّد أنّك رأيت أزرار المشاركة الاجتماعيّة العائمة من قبل. الصورة التالية مثال على هذا النوع من الأزرار: يمكن لهذه الأزرار أيضًا أن تظهر إلى جانب المحتوى إلا أنّ هذا النّوع لم يعد شائعًا كما كان. إحدى العثرات التي يجب الحذر منها بالنّسبة لأزرار المشاركة الاجتماعيّة العائمة هي طريقة ظهورها في أجهزة الهواتف. هل تختفي جميع الأزرار معًا، وإذا كانت تختفي معًا فعلاً، كيف يمكن للمستخدم المشاركة من جهازه بسهولة عن طريق حلّ بديل؟ كل هذه هي أسئلة عليك الإجابة عليها من منظور قابليّة الاستخدام. إذا كانت أزرار المشاركة العائمة تختفي بالفعل فإنّك بحاجة لإيجاد حل بديل سهل الاستخدام لمستخدمي الهواتف النقّالة. إذًا كيف يمكن إضافية خاصيّة أزرار المشاركة الاجتماعيّة العائمة على موقع ووردبريس الخاص بك؟ ستقوم إضافة Floating Social بتنفيذ الأمر ببساطة. لا يوجد هناك الكثير من البدائل في الوقت الراهن ولكن الإضافتين Flare و Digg Digg يمكنهما تقديم الخاصيّة إلا أنّه لم يتمّ تحديثهما منذ فترة. بديل آخر لكل الحلول المعروضة أعلاه هو دمج أزرار المشاركة الاجتماعيّة الخاصّة بك في قائمة التنقّل الثابتة أو في القائمة الجانبيّة الثابتة في موقعك. غيض من فيض تردّدتُ كثيرًا عند كتابة هذا المقال لمعرفتي بأن الطرق التي يمكن استخدامها لزيادة قابليّة استخدام موقعك كثيرة جدًا. رغم ذلك فإنّك في نهاية المطاف اكتفيت بأربعة طرق فقط. هناك الكثير من الطرق إضافة إلى الأربعة طرق المذكورة سابقًا يمكنك استخدامها لتحسين قابلية المستخدم الخاصّة بموقعك. ركّزنا في هذا المقال على بعض الأشياء الأكثر ظهورًا للمستخدم ولكن في الحقيقة فإنّ الأشياء غير المحسوسة هي التي تخلق فرقًا أكبر بالنسبة لقابليّة الاستخدام. على سبيل المثال، تعتبر سرعة التحميل جزءًا كبيرًا جدًّا من قابليّة الاستخدام. إذا استغرق موقعك وقتًا طويلاً في التحميل فإنّ معظم الزّوار سيقومون ببساطة بمغادرة الموقع، في هذه الحالة فإنّ جميع جوانب موقعك ستصبح بلا معنى. مع أخذ ذلك في الاعتبار، يمكنك العمل على كل شيء بدءًا من تحسين الصورة، إلى التخزين المؤقّت، إلى حلول شبكة توصيل المحتوى (Content Delivery Network) ولا تنسى أدوات سرعة الصفحة. ترجمة -وبتصرّف- للمقال 4Quick Ways To Lower Your WordPress Site's Bounce Rate لصاحبه Tom Ewer
  6. سنتعرّف في هذا الدّرس على العبارات الشرطيّة وكيفيّة استخدامها لتنفيذ أوامر أو تجاهلها استنادًا إلى شرط معيّن. افتح ملفّ روبي جديد وسمّه logic.rb أو أيّ اسم آخر مع التأكّد من كتابة rb. في آخر اسم الملفّ واكتب الشيفرات البرمجيّة التّالية والتي تمثّل نسخة مجرّدة من لعبة إلقاء النّرد: number = rand(1..6) puts "You rolled #{number}" ماذا فعلنا هنا؟ أنشأنا متغيّرًا وحفظنا به قيمة عشوائيّة بين 1 و 6، ثمّ استعملنا هذا المتغيّر لطباعة القيمة العشوائيّة على الشّاشة باستخدام أمر puts مخبرين المستخدم أنّ ناتج إلقائه للنرد هو ذلك الرقم العشوائي النّاتج عن استخدام دالّة rand (التي سبق وأن اطّلعنا عليها في الدّرس السّابق). سنتعرّف الآن على بعض العبارات الشرطيّة التي يمكننا استخدامها لإخراج بعض المعلومات عن الرقم استنادًا إلى ما إذا كان الشّرط متحقّقًا أم لا. اكتب السطر التّالي أسفل الشيفرات البرمجيّة السّابقة: puts "You rolled the highest number possible" if number == 6 تلاحظ في العبارة الشرطيّة السّابقة أنّ الشرط هو أن يكون المتغيّر number يساوي 6. إذا تحقّق هذا الشرط سنقوم بإخراج رسالة "You rolled the highest number possible". الأمر المهم لدينا هنا هو عبارة if التي تأتي قبل الشّرط الذي يجب أن يكون صحيحًا من أجل طباعة السّلسلة، في حالتنا هذه كما ذكرنا فالشّرط هو أن يكون المتغيّر مساويًا لـ 6. لاحظ كيف استخدمنا علامتي == لاختبار المساواة بين الطرفين. يختلف هذا عمّا فعلنا في بداية الشيفرات حيث استخدمنا علامة مساواة واحدة لتعيين قيمة للمتغيّر. إذًا فنستخدم علامة يساوي واحدة لتعيين القيم وعلامتين من أجل اختبار إذا كان طرفين متساويين أم لا. يمكننا أيضًا استخدام بنية مشابهة لذلك لمعرفة إذا كان الشّرط غير متحقّق كالتّالي: puts "You didn't roll the lowest number possible" if number != 1 كما تلاحظ فالجملة مشابهة إلى حدٍّ كبير، نريد طباعة هذه السلسلة إذا كان المتغيّر number لا يساوي (!=) 1. سيتم طباعة تلك السلسلة فقط عن تحقّق هذا الشرط. في الحالتين السّابقتين لدينا الجملة الشّرطيّة موجودة بالنهاية والشيفرة البرمجيّة التي نريدها أن تنفّذ موجودة في البداية. يمكننا كتابة ذلك بترتيب مختلف بأن نضع الجملة الشّرطيّة في البداية كالتّالي: if number < 5 then puts "You rolled a number less than 5" end كما تلاحظ، نحن نخبر روبي إذا كان قيمة المتغيّر أقل من 5 يجب تنفيذ الأمر الموجود بعد الكلمة المفتاحيّة then. وبالنّهاية نضع end والتي نحتاج إليها لإخبار روبي بأنّ عبارة if قد انتهت. كتابة أكثر من شرط يمكننا أيضًا كتابة أكثر من شرط في أكثر من سطر. مثال على ذلك: if number.even? puts "You rolled and even number" else puts "You rolled an odd number" end السّطر الأوّل يتحقّق إذا كان المتغيّر number عددًا زوجيًّا باستخدام دالّة even، إذا كانت الإجابة true سيتمّ تنفيذ أمر puts الخاصّ بهذا الشرط. إذا كانت قيمة المتغيّر عددًا غير زوجي، فمن البديهي أنه سيكون فرديًّا. إذًا فإنّ else تعدّ بمثابة ما نريد تنفيذه إذا لم يتحقّق الشرط. لاحظ أنّه يجب وضع end مرّة واحدة في النهاية تمامًا وليس بعد if مرّة وبعد else مرّة. elsif يمكننا كتابة عدد أكبر من الجمل الشرطيّة أيضًا باستخدام elsif. if number == 1 then puts "You rolled one" elsif number == 2 then puts "You rolled two" elsif number == 3 then puts "You rolled three" else puts "You rolled a number bigger than three" end لدينا في هذا المثال ثلاثة جمل شرطيّة مختلفة متبوعة بجملة else والتي ستُنفّذ إذا لم يتحقّق أيّ شرط من الشّروط الثلاثة السّابقة لها. لنبدأ مع أول سطر، جملة if عاديّة تتحقّق إذا كانت قيمة المتغيّر number تساوي 1، إذا كان الجواب نعم فستنفّذ روبي الأمر الموجود بعد then وتستبعد باقي الجمل الشرطيّة. أمّا إذا لم تتحقّق الجملة الشرطيّة الأولى فتنتقل روبي إلى السطر التّالي والذي يحتوي على جملة شرطيّة أخرى والتي تختبرها روبي فقط إذا لم تتحقّق الجملة الشرطيّة السّابقة، لذلك فهي تسمّى elsif. تعمل تمامًا elsif عمل if، الفرق فقط هو أنّها لا تنفّذ في حالة تحقّق الجملة الشرطيّة السّابقة لها. السطر الثالث مشابه للسطر الثّاني. وبالنهاية لدينا else والتي لا تحتوي على شرط محدّد وإنّما تنفّذ في حال عدم تحقّق أي جملة شرطيّة من الثلاث. ثم end. عبارة Case يمكننا استخدام عدد لا نهائي من جمل if, elsif, else ولكن مع زيادى عدد الشروط المطلوبة قد يصبح الأمر متعبًا ومستهلكًا للوقت. لذلك فهناك عبارة أخرى يمكننا استخدامها وهي case. حاول تخمين ما تفعله case بالاطّلاع على الشيفرات التالية: case number when 4 then puts "You rolled four" when 5 then puts "You rolled five" when 6 then puts "You rolled six" else puts "You rolled a number less than four" end كما تلاحظ، فهي تعمل بشكل مشابه جدًّا للمثال السّابق. الفرق أنّنا نستخدم case بدلاً من if. لاحظ أنّنا نضع بالبداية المتغيّر number حيث أنّ كل الجمل الشّرطيّة الموجودة بـ case تشير إلى هذا المتغيّر. على سبيل المثال بالنّظر إلى السطر الثاني، فهو يشير أنّه عندما (when) تكون قيمة المتغيّر number تساوي 4 إذًا (then) ننفّذ أمر puts. وهكذا حتى الوصول إلى else ثم end في نهاية عبارة case واللذان يستخدمان تمامًا مثل استخدامهما في عبارة if. سلسلة عبارات if يمكننا أيضًا وضع جمل if كمتسلسلات كما ترى أدناه: if number == 2 or number == 3 or number == 5 puts "You rolled a prime number" end استخدمنا جملة if عاديّة ونخبر روبي بأنّه إذا كانت قيمة المتغيّر number تساوي 2، أو (or) تساوي 3، أو (or) تساوي 4 فكما قد تكون توقّعت سيتمّ تنفيذ الأمر الخاصّ بتلك العبارة. إذًا فنحن في الواقع نختبر ثلاث شروط مختلفة وإذا تحقّق شرط واحد منها فإنّ ناتج هذه العبارة الشّرطيّة سيصبح true. هناك طريقة أخرى لكتابة تلك الشيفرات. puts "You rolled a square number" if number == 1 || number == 4 يسمّى || برمز الأنبوب المزدوج (Double Pipe Symbol) والذي يمثّل كلمة or. لاحظ أيضًا كيف قمنا بعكس الجملة الشرطيّة وذلك بوضع الشرط في النهاية كما فعلنا سابقًا. هناك أيضًا عبارة and والتي تتحقّق إذا تحقّقت جميع الشروط الموجودة والتي مربوط بينها باستخدام and. if number.odd? and number >= 4 puts "You rolled five" end في الشيفرات البرمجيّة أعلاه نتحقّق إذا كانت قيمة المتغيّر هي عدد فردي و (and) أكبر من أو تساوي 4. هذا الرّمز >= يعني أنّ الطرف الأيسر من الجملة أكبر من أو يساوي الطرف الأيمن. بالرجوع مجدّدًا إلى الشيفرة البرمجيّة السّابقة فإنّه عند تحقّق الشرطين معًا (وليس أحدهما فقط) فسيتمّ تنفيذ الأمر puts الذي يلي العبارة الشرطيّة. مثل or، هناك أيضًا طريقة أخرى لكتابة and. if number.even? && number <= 3 puts "You rolled two" end الشيفرة أعلاه مشابهة تمامًا للسّابقة، نتحقّق إذا كانت قيمة المتغيّر عددًا زوجيًّا و (&&) أقل من أو تساوي 3. إذا تحقّق الشّرطيّن المربوط بينها باستخدام && فسيتمّ تنفيذ أمر puts الخاصّ بالعبارة الشرطيّة. رمز && يسمّى Double Ampersand Symbol. ختام تعرّفنا في هذا الدّرس على العبارات الشرطيّة في ruby وكيفيّة استخدامها. إذا كتبت الشيفرة البرمجيّة المستخدمة في هذا الدّرس في ملفّ روبي فعلاً فجرّب تنفيذها في سطر أوامر روبي التفاعليّ كما تعلّمنا في الدّروس السّابقة وقارن النتائج بالشيفرات الموجودة لمعرف وظيفة كل جزء منها.
  7. سنتعرّف في هذا الدّرس على كيفية التّعامل مع الأرقام في روبي. سنقوم في البداية بالتعامل مع العمليّات الحسابيّة من خلال سطر أوامر روبي التفاعليّ. ثمّ سنتعرّف بعد ذلك على الأعداد الصحيحة Integers والدوال الخاصّة بها. كما سنتعرف أيضًا على كيفية توليد أرقام عشوائيّة في روبي. الأرقام لنلق الآن نظرة على استخدام الأرقام في سطر أوامر روبي التفاعليّ. افتح الطرفيّة وابدأ جلسة IRB جديدة عن طريق كتابة أمر irb. يمكننا كتابة عمليّة جمع كالتالي: 3 + 5 علامة الجمع في الأمر السّابق هي عبارة عن دالّة خاصّة بالرقم 3 (الذي يعدّ كائنًا، كما ذكرنا سابقًا أن روبي تتعامل مع أي شيء على أنّه كائن له دوالّ خاصّة به). قد تتساءل كيف لعلامة + أن تكون دالّة وقد تعرّفنا أن استدعاء الدوال يتم عن طريق إضافة نقطة ثم اسم الدّالّة بعد الكائن. دعني أخبرك أنّه يمكن بالفعل تنفيذ الدّالّة + بهذه الطريقة. ولأنّنا نريد إضافة 5 إلى 3 فإنّنا نريد إضافة ما يسمّى بالمعطى Argument والذي يوضع بين قوسين بعد اسم الدّالّة. لذلك فيمكن إعادة كتابة الأمر السّابق هكذا: 3.+(5) إذا كتبت الأمرين ستحصل على نفس النّتائج. إذًا فرقم 3 هو الكائن الذي يستدعي الدّالّة، علامة الجمع هي اسم الدّالّة وبين القوسين نجد المعطى هو رقم 5. ولأنّه عند كتابة عمليّة الجمع بهذه الطريقة يبدو الأمر صعبًا بعض الشيء، فهذا الاستدعاء لا يبدو كعمليّة الجمع المألوفة لنا. لذلك فإنّ روبي تسمح لنا باستخدام الدّالّة بالصورة الأولى والتي تبدو أسهل في القراءة والاستخدام لإتمام عمليّات الجمع. يسمّى هذا بالتجميل اللّغوي Syntactic Sugar. لذلك فإن الطريقة الأولى لإتمام عمليّة الجمع هي الأكثر شيوعًا عن التنويت النقطي Dot Notation. لدى روبي الكثير من العمليّات الحسابيّة الأخرى. مثل الطرح: 10 – 4 الضرب: 4 * 8 القسمة: 9 / 2 إذا كنت تنفّذ الأوامر السّابقة في سطر أوامر روبي التفاعليّ ستلاحظ أنّ ناتج عمليّة قسمة 9 على 2 هو 4، وهذا ليس صحيحًا فحاصل قسمة 9 على 2 هو 4.5 وليس 4، أليس كذلك؟ حدث ذلك لأنّ 9 و2 هي أرقام صحيحة ممّا يعني أنّ الناتج سيكون أيضًا الجزء الصحيح فقط من خارج القسمة وهو في هذه الحالة 4 بدلاً من 4.5. للحصول على الناتج الصحيح لهذه العمليّة نحتاج إلى استخدام نوع آخر من كائنات الأرقام يسمّى بالعدد العشري Float. لاستخدام عدد عشري بدلاً من عدد صحيح كل ما علينا فعله هو على سبيل المثال كتابة 9.0 بدلاً من 9. جرّب إعادة كتابة عمليّة القسمة السّابقة باستخدام 9.0. ستجد أنّ روبي قد أعادت النّاتج 4.5. دالتا even وodd تستخدم روبي دالتين لمعرفة ما إذا كان العدد زوجيًّا أم فرديًّا. على سبيل المثال اكتب الأمر التّالي ولاحظ النّتيجة: 62.even? بعد الضغط على Enter ستطبع روبي على الشّاشة true ردًّا على سؤالنا لها هل العدد 62 عددًا زوجيًّا؟. يمكننا أيضًا استخدام دالّة odd للتحقّق ممّا إذا كان العدد 62 زوجيًّا أم فرديًّا هكذا: 62.odd? تحدّثنا في الدّرس السّابق عن دوال Bang وكيف أنّها تنتهي بعلامة تعجّب. دالّتي even و odd هما مثالين للدوال الشرطيّة وهي الدوال التي ترجع true أو false وغالبًا ستجد علامة استفهام بنهاية تلك الدوال والتي تجعل من السّهل تمييز هذا النّوع. دالة GCD يمكن لروبي تنفيذ بعض العمليّات الحسابيّة اللّطيفة أيضًا. على سبيل المثال يمكن إيجاد القاسم المشترك الأكبر لعددين (وهو أكبر عدد يقسم في نفس الوقت العددين معًا بدون أيّ باقي قسمة) باستخدام دالّة gcd. إذًا لو أردت معرفة القاسم المشترك الأكبر لكلٍّ من 12 و20 فيمكن كتابة هذا كالتّالي: 12.gcd(20) وستكون النتيجة 4 دالة LCM دالّة lcm مشابهة نوعًا ما لدالّة gcd وتقوم بإيجاد المضاعف المشترك الأصغر لعددين (وهو أصغر عدد موجب صحيح مضاعف لكلا هذين العددين، أي أنّه يمكن قسمة هذا المضاعف المشترك الأصغر على العددين بدون باقي قسمة). إذا أردت معرفة المضاعف المشترك الأصغر لكل من 15 و20 يمكن كتابة هذا كالتّالي: 15.lcm(20) وستكون النتيجة 60 دالة to_s آخر دالّة خاصّة بالأعداد الصحيحة التي سنتطرّق إليها هي دالّة to_s والتي هي اختصار لـ to string. يمكنك من اسمها تخمين وظيفتها، تقوم الدّالّة بتحويل عدد صحيح إلى سلسلة حرفيّة تحتوي على هذا الرقم. على سبيل المثال، الشيفرة البرمجيّة التالية تقوم بتحويل العدد الصحيح 7 إلى سلسلة "7": 7.to_s بعد الضغط على Enter سيتم إرجاع القيمة هكذا "7". نعرف أنّ القيمة نوعها سلسلة من علامات الاقتباس المحيطة بها. الآن يمكننا التّعامل مع هذا الرقم على أنّه سلسلة وتنفيذ دوال السّلاسل عليه. دالة to_i دالّة to_i مشابهة لدالّة to_s ولكنّها خاصّة بالسّلاسل، تقوم الدّالّة بتحويل السلسلة إلى عدد صحيح. لذلك فيمكننا كتابة "42" وتحويلها إلى عدد صحيح هكذا: "42".to_i سنلاحظ بعد تنفيذ الأمر إرجاع قيمة صحيحة عبارة عن 42 وستختفي علامات الاقتباس المحيطة بالعدد. بذلك يمكننا استخدام الدوال الخاصّة بالأعداد الصحيحة على 42، مثل الجمع والطّرح. عليك توخّي الحذر عند التّعامل مع هذه الدّالّة، حيث أنّه في حالة عدم احتواء السلسلة على أيّة أرقام فسوف تقوم بإرجاع قيمة 0. على سبيل المثال اكتب الأمر التّالي ولاحظ الناتج: "Hello World".to_i أمّا في حالة تنفيذ الدّالّة على سلسلة تبدأ بقيمة عدديّة فستقوم الدّالّة بتحويل وإرجاع الرقم الموجود في أوّل السلسلة فقط. مثال على ذلك: "2016 Jan".to_i دالة Rand يُعدّ توليد أرقام عشوائيّة أحد الأمور المفيدة في البرمجة وله استخدامات عديدة، يمكن فعل ذلك في ruby بسهولة عن طريق استخدام دالّة rand. باستخدام الدّالّة يمكننا توليد عدد عشري بين 0 و 1.0. كلّ ما عليك فعله هو كتابة rand في سطر أوامر روبي التفاعليّ والضّغط على Enter، جرّب كتابة الأمر أكثر من مرّة ولاحظ كيف تختلف القيمة في كلّ مرّة ولكنّها لا تزيد عن 1.0 ولا تقلّ عن 0. ولكن ماذا إذا أردت الحصول على أرقام عشوائيّة صحيحة؟ إذا أضفت عددًا صحيحًا للدّالّة كمُعطى فستقوم الدّالّة بتوليد عددًا عشوائيًّا صحيحًا بين 0 والعدد المعطى ولكن العدد المعطى لن يكون ضمن تلك الأعداد العشوائيّة. فمثلاً إذا أعطيت الدّالّة رقم 6 ستقوم بتوليد رقمًا عشوائيًّا بين 0 و 5: rand(6) ماذا لو أردت البدء من 1 بدلاً من 0؟ توفّر روبي طريقة لطيفة لفعل ذلك. كلّ ما علينا فعله هو إدخال مجال range معيّن من القيم كمُعطى للدّالّة فنكتبها هكذا: rand(1..6) الأمر السّابق يخبر روبي بأن تختار رقمًا عشوائيًّا بين 1 و 6، متضمّنة 1 و 6 أيضًا ضمن الأرقام العشوائيّة. يذكّرنا هذا بلعبة إلقاء النّرد، أليس كذلك؟ خاتمة تعرّفنا في هذا الدّرس على بعض المفاهيم المهمّة في روبي مثل الأرقام والدوال الخاصّة بها وكيفيّة تحويل رقم إلى سلسلة والعكس. هدف هذا الدّرس هو إعطاؤك لمحة سريعة عن العمليات التي يُمكن تنفيذها على الأرقام ومبدأ عمل ذلك. بطبيعة الحال لم نستعرض سوى عدد محدود من الدّوال. بإمكانك الاطّلاع على باقي الدّوال عبر زيارة التّوثيق الرّسمي للغة وخاصة صفحة الأرقام الصّحيحة.
  8. تعرّفنا في الدّرس السّابق على لغة روبي ووميزاتها. في هذا الدّرس سوف نستعرض بعض أنواع البيانات في Ruby، وسنتعرّف باستفاضة على نوع السلاسل. كما سنتعرّف على أحد أهمّ سمات أيّ لغة برمجة، ألا وهي المتغيّرات. سنستخدم في الجزء الأول من الدّرس سطر أوامر روبي التفاعليّ. افتح الطرفيّة وابدأ جلسة irb عن طريق كتابة أمر irb والضغط على زر Enter. القيم والأنواع القيمة هي أبسط شيء يتعامل معه البرنامج مثل حرف أو رقم. تعرّفنا في الدّرس السّابق على بعض تلك القيم. تختلف القيمة 2 عن القيمة "Hello World"، حيث أن الأولى هي عدد صحيح Integer أمّا الثّانية فهي من نوع سلسلة String، جاءت التسمية من كونها سلسلة من الأحرف. يمكنك التعرّف بسهولة على السلاسل من خلال علامات الاقتباس المحيطة بالقيمة. هناك نوع آخر يسمّى Float وهو أيّ رقم يحتوي على علامة عشريّة، مثلاً: 2.5، 13.6، 4.0. ملحوظة: قد تعتقد أن "12" و"1.5" هي أرقام وتتعامل معها في برنامجك على ذلك فتنفّذ عليها عمليّات حسابيّة وتكتشف بعد ذلك أنّ مفسّر روبي يظهر لك علّة برمجية Bug. سبب ذلك أنّها ربّما تكون أرقامًا بالنسبة لك ولكن المفسّر يعتبرها سلاسل نصيّة حيث أنّها محاطة بعلامات الاقتباس والمفسّر مُبَرْمَج على تصنيف أيّ شيء بين علامات اقتباس على أنّه سلسلة. تريد التأكد من ذلك بنفسك؟ جرّب جمع "12" + "1.5". أو بطريقة أخرى يمكنك استخدام الدّالة المدمجة is_a لسؤال روبي هل هذه القيمة نوعها Integer مثلاً وستردّ عليك روبي true أو false. فمثلاً إذا أردت التأكّد من نوع قيمة معيّنة مثل 12 اكتب الأمر التالي: 12.is_a?(Integer) الآن للعودة إلى ما إذا كان كل من "12" و"1.5” أرقامًا أم سلاسل، جرّب الأوامر التالية (تأكّد من كتابة أوّل حرف بشكل كبير Capital): "12".is_a?(Integer) "1.5".is_a?(Float) أحيانًا عند كتابة أعداد كبيرة قد تجد نفسك محتاجًا إلى إرفاق فواصل لجعل العدد قابلاً للقراءة أكثر، مثلاً 1,000,000. لو فعلت ذلك في روبي ستحصل على خطأ. ولكن يمكنك فعل ذلك مع الأمر puts. مثلاً يمكن كتابة: puts 1,000,000 ماذا كانت النتيجة؟ لم تتوقعها أليس كذلك؟ قامت روبي قامت بطباعة: 1 0 0 رقم 1 و 0 و 0 في أسطر مختلفة. حدث ذلك لأنّ روبي قد فسّرت هذا العدد على أنّه ثلاثة أرقام مستقلّة ومفصول بينها بفواصل. في روبي يمكن استخدام الأمر puts لطباعة أكثر من قيمة في أكثر من سطر عن طريق الفصل بين تلك القيم بفاصلة. فمثلاً لو أردت طباعة "Hello" في سطر وبعدها "World" في سطر باستخدام أمر روبي واحد يمكن استخدام الأمر التالي: puts "Hello", "World" Hello World السلاسل السلاسل في روبي هي مجموعات من الأحرف. يمكن إنشاء سلسلة نصيّة عن طريق كتابة أحرف ونصوص داخل علامتي اقتباس مزدوجة. مثلاً لكتابة سلسلة تحتوي على نصّ Hello Ruby اكتب الأمر التّالي: "Hello Ruby" يمكن استخدام علامة الاقتباس المفردة أيضًا لإنشاء سلسلة في روبي، لذلك فيمكن إنشاء السلسلة السّابقة كالتّالي: 'Hello Ruby' إذا أردت استخدام أحد نوعي علامات الاقتباس في داخل نصّك فعليك استخدام النّوع الآخر لإنشاء السلسلة فمثلا لو أردت إنشاء سلسلة نصيّة بها I'm learning Ruby، واستخدمت علامة الاقتباس المفردة لإنشاء السلسلة سيؤدّي ذلك إلى حدوث خطأ ولن يتمّ تنفيذ الأمر. لذلك فالطريقة الصحيحة لكتابة هذه السلسلة هو استخدام علامة الاقتباس المزدوجة: "I'm learning Ruby" مثال آخر: puts '"Never memorize something that you can look up." -Albert Einstein' خيار آخر لاستخدام علامات الاقتباس في السلاسل يسمّى هروب علامة الاقتباس escaping، يحدث هذا عن طريق وضع خط مائل عكسي Backslash قبل علامة الاقتباس والذي سيؤدّي إلى اعتبارها حرفًا عاديًّا بدلاً من تنفيذها كوسيلة لإنشاء سلسلة. يمكن إذًا كتابة السلسلتين السّابقتين كالتّالي: 'I\'m learning Ruby" "\"Never memorize something that you can look up.\" -Albert Einstein" ذكرنا في الدّرس الأوّل أنّ كل شيء في روبي هو كائن Object. يمكن للكائنات تنفيذ أفعال يُطلق عليها اسم دوال. هناك الكثير من الطرق لجعل كائن ينفّذ دالّة ولكن الطريقة الأكثر شيوعًا هي التنويت النُقطي Dot Notation وهو عبارة عن أن تكتب الكائن (في مثالنا هذا الكائن هو السلسلة "Hello Ruby") متبوع بنقطة ثم اسم الدّالة التي تريد استدعاءها. لنجرّب استدعاء الدّالة length والتي هي دالّة مدمجة في روبي تقوم بإرجاع طول السلسلة أو بمعنى آخر عدد الأحرف الموجودة في السلسلة: "Hello Ruby".length المتغيرات أحد أقوى السمات في أيّ لغة برمجة هي القدرة على التعامل مع المتغيّرات. المتغيّر ببساطة هو عنوان (أو "اسم") يشير إلى قيمة معيّنة. بمعنى آخر فالمتغيّر هو طريقة لحفظ الكائنات في الذّاكرة من أجل الاستخدام لاحقًا. يمكن في روبي تعيين متغيّر إلى كائن بسهولة باستخدام عامل التساوي (Equals Operator =): name = "Sara" في هذا المثال، اسم المتغيّر يشير إلى السلسلة "Sara". يعني هذا أنّه بإمكاننا استدعاء دوال مختلفة مباشرةً على اسم المتغيّر بدلاً من كتابة السلسلة في كلّ مرة أردنا استدعاء دالّة. الآن إذا أردت استدعاء الدّالة length لحساب طول السلسلة يمكن ببساطة كتابة ذلك كالتّالي: name.length لنجرّب الآن بعض دوّال روبي التي يمكن استخدامها مع السّلاسل في روبي (السّلاسل عبارة عن كائنات في روبي) على هذا المتغيّر. على سبيل المثال، دالّة reverse ستقوم بطباعة السلسلة معكوسة: name.reverse دوال upcase و downcase من الدوال الخاصّة بالسلاسل أيضًا دالّتا upcase و downcase. تقوم دالّة upcase بتحويل كل الأحرف الموجودة في السلسلة النصيّة إلى أحرف كبيرة Capital Letters. أمّا دالّة downcase فتحوّل كل الأحرف الموجودة في السلسلة إلى أحرف صغيرة Small Letters. جرّب استدعاء الدّالتين على المتغيّر name: name.upcase name.downcase هناك عدد كبير جدًا من الدوال الخاصّة بالسلاسل يمكنك التعرّف على جميعها عن طريق استخدام دالّة methods (نعم هذا هو اسمها) على المتغيّر الخاصّ بك، هكذا: name.methods عند تنفيذ الأمر ستقوم روبي بعرض جميع الدوال المختلفة التي يمكن لهذا النوع من الكائنات استخدامها. يمكنك أيضًا معرفة أكثر عن تلك الدوال عن طريق قراءة التوثيقات الخاصّة بها. دوال Bang ربّما لاحظت أن جميع الدوال التي استخدمناها حتّى الآن لم تغيّر شيئًا في السلسلة، فمثلاً إذا أردتُ معرفة القيمة الموجودة في المتغيّر name من جديد سأجد أن القيمة ما زالت كما عيّنتها من البداية (لمعرفة قيمة متغيّرك فقط اكتب اسم المتغيّر واضغط Enter أو استخدم puts إن أردت). لم تتغيّر القيمة وتصبح السلسلة معكوسة ولا جميع الحروف كبيرة أو صغيرة. لكن ماذا لو أردت فعلاً تغيير تلك القيمة؟ سنجرّب بعض الدوال التي تقوم بالفعل بتغيير قيمة السلسلة. أنشئ متغيّرًا باسم fruit واجعله يساوي السلسلة "apple". يمكن تغيير قيمة ذلك المتغيّر عن طريق استدعاء دوال تسمّى بدوال Bang، تنتهي تلك الدوال بعلامة التعجّب أو ما يسمّى برمز Bang. فمثلاً لو أردت تنفيذ الدالة reverse على السلسلة الخاصّة بك وحفظ القيمة الجديدة بدلاً من القيمة الأصليّة يمكن كتابة ذلك ببساطة هكذا: fruit.reverse! عندما نقوم بطباعة المتغيّر بعد ذلك نلاحظ تغيّر القيمة إلى elppa بدلاً من القيمة السّابقة apple. بهذا نكون قد استغنينا تمامًا عن القيمة الأصليّة واستبدلناها بالقيمة الحاليّة. معظم الدوال الخاصّة بالسلاسل لديها دالّة Bang مماثلة. على سبيل المثال هناك أيضًا دالّة Bang مقابلة لدالّة upcase العاديّة. إذًا فيمكننا كتابة: fruit.upcase! سيطبع هذا الأمر قيمة السلسلة بأحرف كبيرة وأيضًا من جديد سيتمّ استبدال القيمة السابقة بالقيمة الجديدة والتي هي ELPPA. إذا كانت هناك علامة تعجّب Bang في نهاية دالّة روبي فهذا غالبًا يعني كن حذرًا، يمكن لهذه الدالّة أن تكون خطرًا. في حالة الأمثلة السّابقة فهي تعني أنّ قيمة السلسلة ستتغيّر فيجب أن تكون حذرًا متى قمت باستخدام هذه الدوال. تسلسل الدوال قد يكون راودك تساؤل حول ماذا لو أردت تنفيذ العديد من الدوال على أحد المتغيّرات، هل يجب كتابة استدعاء الدالّة على المتغيّر لكل دالّة على حدة؟ لحسن الحظّ يمكن استدعاء أكثر من دالة في وقتٍ واحد على نفس المتغيّر. على سبيل المثال إذا عدنا من جديد إلى المتغيّر name وأردنا كتابته معكوسًا وبأحرف كبيرة، يمكن كتابة ذلك تسلسليًّا هكذا: name.reverse.upcase ولكن تذكّر دائمًا أنّه يتمّ تنفيذ الدوال بالترتيب من اليسار إلى اليمين. رغمّ أنّها لا تهمّ في حالة المثال أعلاه، فحتى إذا بدّلنا الترتيب ستكون النتيجة مشابهة. إلا أنّه يمكن أن يتغيّر النّاتج عن النّاتج الذي تتوقعه في حالات أخرى، لذلك يجب التحقّق من الترتيب عند استخدام هذه الطريقة في استدعاء الدوال. إدراج شيفرات برمجية في السلاسل يمكن بطريقة بسيطة جدًا إدراج شيفرات برمجيّة في سلاسل نصيّة وتنفيذ تلك الشيفرات. يمكن فعل ذلك عن طريق وضع الشيفرات البرمجيّة داخل حاضنات Curly Brackets مع إضافة رمز التلبيد Hash في البداية: "Hello my name is #{name}" يطبع هذا نصًا يحتوي على الجملة المكتوبة بالإضافة إلى النصّ الموجود في المتغيّر name الذي قمنا بإنشائه سابقًا. لذلك فالسلسلة السابقة ستصبح "Hello my name is Sara". ما حدث هو أنّه قد تمّ إدراج قيمة المتغيّر name بداخل السلسلة حيث أنّ علامة التلبيد مع الحاضنات تخبر روبي بأن الموجود بينها هو شيفرات يجب على روبي تنفيذها أولاً وليس طباعتها كما هي. هناك أمر مهمّ عليك تذكّره وهو أنّه عند استخدام شيفرات برمجيّة بداخل سلسلة فلا بد من استخدام علامات الاقتباس المزدوجة. إذا استخدمت علامات اقتباس مفردة فسيتمّ طباعة النصّ كما هو {Hello my name is \#{name. والخط المائل هذا يعني أنّه قد تمّ تخطي هذه القيمة وطُبعت كما هي، مثلما رأينا في السّابق مع 'I\'m'. تطبيق عملي الآن بعد التعرّف على المتغيّرات والسلاسل حان الوقت لكتابة برنامج حقيقي باستخدامهما. في هذا البرنامج سيتمّ طباعة سلسلة نصيّة تسأل المستخدم عن اسمه، ثمّ يقوم البرنامج بعد ذلك باستخدام الاسم الذي سيدخله المستخدم لتطبيق بعض الدوال التي تطرّقنا إليها. أوّلاً نحتاج لإنشاء ملفّ روبي، سمّه ما تريد ولكن لا تنس إضافة rb. إلى نهاية اسم الملفّ. لقد أسميتُ ملفّي greetings.rb. بدايةً سنحتاج إلى طباعة رسالة للمستخدم لسؤاله عن اسمه. لفعل ذلك سنستخدم الأمر puts: puts "Hello, what's your name?" بعد ذلك سنحتاج إلى تمكين المستخدم من كتابة اسمه. أمر gets أمر gets هو اختصار لـ get string والذي يقوم بإيقاف البرنامج وانتظار عمليّة إدخال من المستخدم قبل متابعة تنفيذ البرنامج. سيكون المُدخَل عبارة عن سلسلة كما هو واضح من اسم الأمر. إحدى دوال السلاسل دالّة تسمّى chomp يمكن تطبيقها على سلسلة لحذف الحرف الذي يتمّ إضافته افتراضيًّا للسلسلة بعد الضغط على Enter، حيث أنّه عند استقبال إدخال من المستخدم وبضغطه على زرّ Enter يتمّ تلقائيًّا إضافة حرف سطر جديد إلى نهاية السلسلة. إذًا لتمكين المستخدم من إدخال اسمه نحتاج إلى استخدام أمر gets للحصول على المدخل واستدعاء دالّة chomp لحذف الحرف الزائد وحفظ ناتج ذلك في متغيّر لاستخدامه في وقتٍ لاحق. نكتب ذلك في روبي كالآتي: name = gets.chomp وأخيرًا سنقوم بكتابة شيفرات برمجيّة تتعامل مع هذا المدخل وتطبع بعض المعلومات عنه، أضف ما يلي بعد الأمرين السّابقين في ملفّ روبي الخاصّ بك: puts "Hello #{name}. Your name's length is #{name.length}. That's not really long! Your name backwards is #{name.reverse.downcase.capitalize}" ليُصبح كامل الملف على النّحو التّالي: puts "Hello, what's your name?" name = gets.chomp puts "Hello #{name}. Your name's length is #{name.length}. That's not really long! Your name backwards is #{name.reverse.downcase.capitalize}" يقوم هذا الأمر بطباعة سلسلة نصيّة تحتوي على شيفرات برمجيّة تطبع اسم المستخدم، عدد الأحرف في اسم المستخدم واسم المستخدم معكوسًا. لاحظ في الجزء الثالث كيف أضفنا تسلسل دوال من ثلاث دوال، إحداها هي دالّة جديدة تسمّى capitalize. تقوم دالّة capitalize بتغيير الحرف الأوّل فقط من السلسلة وتحويله إلى حرف كبير على عكس دالة upcase التي تحوّل جميع أحرف السلسلة. احفظ الملفّ بعد كتابة الشيفرات البرمجيّة كاملة ثم قم بتنفيذه عن طريق فتح الطرفيّة والتوجّه إلى مسار المجلّد الذي قمت بحفظ الملفّ به ثم كتابة ruby متبوعًا باسم الملف (أي أنه في حالتي سأكتب الأمر ruby greetings.rb)، إذا واجهتك مشكلة في ذلك فراجع كيف قمنا بعمل ذلك في الدّرس الأوّل. خاتمة بهذا نكون قد انتهينا من الدّرس الثاني وتعرفنا على بعض المفاهيم الأساسيّة في روبي. جاء دورك للتطبيق وحدك، قارن ما يفعله البرنامج بالشيفرات البرمجيّة الخاصّة به للتعرّف أكتر على وظيفة كل جزء. طبّق أيضًا استخدام دوال أخرى لم نستخدمها في البرنامج. كذلك ربّما تريد تجربة كتابة اسمك ثنائيًّا أو ثلاثيًّا مع إضافة مسافة بين كل اسم، هل يتمّ حساب المسافة كحرف ضمن الاسم؟ ابحث في الدوال الخاصّة بالسلاسل عن سلسلة تعالج هذا الأمر وطبّقها.
  9. روبي هي لغة برمجة كائنيّة التوجّه بسيطة وقويّة في ذات الوقت، تم تطويرها في منتصف التسعينات بواسطة عالم الحاسوب Yukihiro Matsumoto والشهير باسم Matz. كان هدفه من تطوير اللغة جعل البرمجة أكثر متعةً وإنتاجيّة. تعمل اللُّغة على العديد من أنظمة التشغيل، مثل ويندوز، ماك والنسخ المختلفة من UNIX. مميزات لغة روبي مفتوحة المصدر ذات توجّهات عامّة (general purpose) كائنيّة التّوجّه ديناميكيّة ومفسّرة محمولة صيغة نظيفة مفتوحة المصدر كون اللّغة مفتوحة المصدر يعنى أنّه يوجد عدد غير منتهي من المطوّرين قائمين على اللّغة، وسرعة في معالجة الأخطاء. ذات توجهات عامة يعنى إمكانية استخدامها في أنواع مختلفة من البرامج، سواء في قواعد البيانات أو واجهات رسوميّة أو برامج علميّة أو الويب، إلى آخره. لغة كائنية التوجه الميزة هي أنّها الأسلوب الأفضل والآمن لتطوير البرمجيّات. دينامكية لن تكون مضطرًا أن تعلن عن نوع المتغير، بعكس لغات أخرى مثل Java. مفسرة بمعنى أنها تستخدم مفسّرًا وليس مترجمًا (المترجم: هو برنامج يقوم بتحويل الشيفرات البرمجيّة من لغة مثل C مثلاً إلى ملفّ تنفيذي. أمّا المفسر: هو برنامج يقوم بتنفيذ الشيفرات البرمجيّة سطرًا بعد سطر وهذا له مميزات وسلبيات. فمن المميزات هي المحموليّة على أكثر من نظام تشغيل وأكثر من بنية من العتاد. بعكس اللّغات المترجمة التي ستحتاج إلى إعادة ترجمة برنامجك كل مرّة لكل منصّة. من السلبيات، البطء وإمكانيّة الإطّلاع على الشيفرات البرمجيّة، إلّا أنّ هذا الأمر لا يعتبر مشكلة في عالم المصادر الحرة) المحمولية بمعنى أنّها مدعومة على العديد من النظم. وكذلك هي لغة بسيطة. Ruby on Rails لروبي قاعدة داعمين مخلصين في اليابان منذ بداية صدورها، إلا أنّ انطلاقتها الحقيقيّة كانت عند إطلاق David Heimmier Hansson لإطار العمل Ruby on Rails والذي يمكن اعتباره سبب شهرة روبي. يجعل إطار العمل Rails من إنشاء تطبيقات الويب عملاً سهلاً وممتعًا، وبديهيًّا فإنّ السبب وراء ذلك هو سهولة لغة روبي في الأساس. الكائنات Objects أحد أهم مبادئ روبي هي أنّ كل شيء في اللُّغة هو كائن. الكائن في البرمجة هو أي كيان له خصائصه المميّزة وأفعاله (المسمّاة دوال Methods). على سبيل المثال، اطّلع على الأسطر البرمجيّة التالية: "hello".reverse => "olleh" 6.even? => true [6,4,3,7].sort => [3,4,6,7] في السّطر الأول، كلمة hello هي كائن يمكن كتابته عكسيًّا بتطبيق الفعل/الدالّة reverse عليه. السّطر الثّاني يشير إلى إمكانيّة التحقّق ممّا إذا كان الرقم 6 (والذي هو كائن في روبي أيضًا) عددًا زوجيًّا أم لا. السّطر الثّالث يوضح أنّه يمكن ترتيب الأرقام تصاعديّا في قائمة باستخدام الدالة sort. تنصيب روبي نحتاج قبل البدء في استخدام روبي إلى تنصيبها أوّلاً. تختلف عمليّة التنصيب قليلاً باختلاف نظام التشغيل المستخدم، كذلك هناك العديد من الطرق لتنصيب روبي، اخترنا أبسطها. Windows إذا كنت تستخدم نظام التشغيل ويندوز فإنّ أفضل طريقة هي استخدام Ruby Installer، اضغط على زرّ Download وانتظر انتهاء التحميل، ثم افتح برنامج Ruby Installer واتّبع التعليمات، في أحد النوافذ سيظهر لك خيار Add Ruby executable to your path، أشّر عليه وتابع عمليّة التّنصيب مثلما تنصّب أي برنامج آخر على ويندوز. Mac إذا كنت تستخدم نظام التشغيل ماك فإنَّ روبي مثبَّتة عليه بشكل قياسي ولكن هناك احتمال كبير أنّ النسخة المثبَّتة ليست أحدث نسخة. لمعرفة نسخة روبي الموجودة لديك، افتح الطرفيّة (وذلك بالبحث عن Terminal وفتحه) واكتب الأمر التالي: ruby -v أبسط طريقة لتنصيب أحدث نسخة من روبي على نظام ماك هو استخدام مدير الحزم Homebrew. بعد تنصيب Homebrew على جهازك، اكتب الأمر التالي في الطرفيّة وسيقوم البرنامج بفعل كل شيءٍ لك: brew install ruby Linux إذا أردت إدارة نُسخ متعدِّدة من روبي على جهازك أو كنت تستخدم نظام لينكس فإنَّ الخيار الأمثل لديك هو استخدام مدير الإصدارات، هناك الكثير من هذه البرامج بما فيها (Ruby Version Manager (RVM. لكي تتمكّن من تنصيب روبي باستخدام RVM، افتح الطرفيّة واكتب الأمر التالي: \curl -L https://get.rvm.io | bash -s stable --ruby يمكنك بعد ذلك معرفة نسخ روبي المنصّبة على جهازك باستخدام أمر: rvm list بعد معرفة النسخ يمكنك تحديد النسخة التي تريدها أن تكون الافتراضيّة عن طريق كتابة أمر: rvm use [Ruby Version] –default حيث [Ruby Version] هو رقم النسخة، مثلا 2.0.0 أو غير ذلك. معرفة إصدار روبي على جهازك كما لاحظت وستلاحظ أيضًا مع تعمّقك في استخدام روبي أنّك ستحتاج في أغلب التنصيبات إلى استخدام الطرفيّة لتنفيذها. هذا الأمر شائع جدًا وستجد أنّك في كثيرٍ من الأحيان تستخدم الطرفيّة لتشغيل سكربتات وكتابة أوامر عندما تتعامل مع روبي. أتوقّع أنّك تعاملت مع الطرفيّة من قبل إذا كنت تستخدم أحد نظامي التشغيل ماك أو لينكس. ولكن على كلّ حال إذا لم تستخدم الطرفيّة من قبل فلا تقلق، ربّما تبدو صعبة في بادئ الأمر ولكن مع الوقت ستلاحظ مدى سهولتها وإنتاجيّتها. سنستخدم الآن الطرفيَّة للتحقُّق من أنّ عمليّة التنصيب تمّت بنجاح. اكتب السطر التالي: ruby -v إذا انتهى التنصيب بنجاح فسيظهر لك اسم نسخة روبي المنصّبة، كما هو ظاهر في الصورة أدناه، تخبرني الطرفيّة أنّ نسخة روبي الموجودة على حاسوبي هي ruby 2.2.3، وهي أحدث إصدار وقت كتابة هذا الدّرس. سطر أوامر روبي التفاعلي يوفّر سطر أوامر روبي التفاعلي (IRB) مجالاً لكتابة شيفرات روبي والحصول على نتائج لحظيًّة حيثُ يتمّ تنفيذ الأمر فور ضغطك على زرّ Enter. تأتي هذه الأداة مدمجة مع روبي، لذلك فلن تحتاج إلى عمليَّات تنصيب إضافيّة. سنجرّب الآن كتابة شيفرات برمجيّة بسيطة للتعرُّف على مدى سهولة اللُّغة في سطر أوامر روبي التفاعليّ والتي تعمل في الطرفيّة مباشرةً. للبدء، كل ما عليك فعله هو فتح الطرفيّة وكتابة أمر irb ثمّ الضغط على Enter. يؤدّي هذا إلى بدء جلسة IRB، أي أنّه الآن بإمكانك كتابة وتنفيذ أوامر روبي. لطباعة Hello World على الشاشة اكتب الأمر التالي: puts "Hello World" puts هو أمر في روبي وهو اختصار لـ put string والذي يطبع السلاسل النصيّة Strings. سلسلة "Hello World" هي كائن روبي يخزّن النصّ المكتوب بين علامتي التنصيص. لنجرّب استخدام الدالّة المذكورة سابقًا reverse على نص "Hello World". اكتب الأمر التالي: puts "Hello World".reverse ستلاحظ ظهور النصّ معكوسًا. النقطة الموجودة بعد السلسلة هي الطريقة التي نضيف بها الدوال إلى الكائنات في روبي. ربّما تريد أن تجرّب الدالّة على نصوص مختلفة أيضًا لفهم طريقة عملها أكثر. العمليات الحسابية يمكن لروبي التعامل مع الأرقام أيضًا فيمكننا إجراء عمليّات حسابيّة مختلفة. جرّب العمليّات الحسابيّة التالية أو عمليّات حسابيّة أخرى من اختيارك: 1 + 1 5 – 7 * 2 456549 * 45 + 23543 كما ذكرنا سابقًا فإنّ روبي تعتبر أن كلّ شيء هو كائن، فالأرقام في روبي إذًا هي كائنات لها خصائص ودوال. اكتب السطر التالي ولاحظ ما سيظهر لك: 2.even? ستجيب عليك روبي true، نعم اثنان هو رقم زوجي (even). لاحظ مدى سهولة لغة روبي. لو عرضت السطر السابق على شخص لا يعرف شيئًا على البرمجة، بنسبة كبيرة جدًا سيفهم المقصود منه. تسمّى القوائم الموجودة بين أقواس مربّعة بالمصفوفة Array. إليك مثال على مصفوفة تحتوي على بعض الأرقام: [2, 7, 4, 8] بديهيًّا فهذه المصفوفة هي كائن، وبالتّالي فهناك دوالّ خاصّة بها. لنجّرب دالّة sort. أضف .sort إلى نهاية المصفوفة: [2, 7, 4, 8].sort ماذا حدث بعد كتابة الأمر؟ تم ترتيب المصفوفة تصاعديًّا. لأنّ الدّالة sort وكما يوضّح اسمها تُرتّب المصفوفة التي تعمل معها ترتيبًا تصاعديًا. العبارات المنطقية مثال آخر على مدى سهولة ووضوح روبي، اكتب السطر التالي في جلسة IRB لديك ثم اضغط Enter: 4.times do لن يحدث شيء ولكن ستلاحظ ظهور علامة (*) بدلاً من علامة (<) بعد رقم السّطر. هذه العلامة توضّح أنّنا لا زلنا في مرحلة كتابة الشيفرات البرمجيّة، بمعنى آخر أنّ الشيفرات البرمجيّة لم تنته بعد. اكتب شيئًا مثل التّالي أو اطبع نصًّا آخر من اختيارك ثمّ اضغط Enter: puts "Ruby is so easy" نهايةً اكتب end في السطر الجديد واضغط Enter لإنهاء مرحلة الإدخال. ربّما يمكنك تخمين ماذا تفعل هذه الشيفرات البرمجيّة قبل حتّى تشغيلها. نحن ببساطة نخبر روبي أن تفعل أمرًا لعددٍ من المرّات. في هذا المثال، نطلب من اللُّغة طباعة النصّ الموجود بين علامتي التنصيص 4 مرّات. إذا لم تفهم ما المقصود تمامًا في الفقرة السّابقة فالمطلوب أن نكتب الأسطر التالية (سطرًا بعد الآخر): 4.times do puts "Ruby is so easy" end كتابة برنامج روبي الآن وبعد أن رأينا كيف تعمل روبي في سطر أوامر روبي التفاعليّ فقد حان الوقت لكتابة روبي وحفظها في ملفّ. افتح محرّر النصوص المفضّل لديك، لا تحتاج إلى برنامج معيّن لكتابة روبي، مجرّد محرّر نصوص بسيط يفي بالغرض. ولكن يفضّل اختيار محرّر نصوص يدعم خاصيّة تعليم الصيغة وتلوينها syntax highlighting. بعض الاقتراحات: Notepad++، Sublime Text. للبدء كل ما علينا فعله هو كتابة ما يلي في الملفّ: puts "Hello World" لاحظ أنّ هذه الشيفرة البرمجيّة مشابهة تمامًا لما كتبناه سابقًا في سطر أوامر روبي التفاعليّ، وبالتّالي فيجب أن نتوقّع نتائج مشابهة عند تشغيل البرنامج. لتشغيل البرنامج علينا أوّلاً حفظ الملفّ. أقترح عليك إنشاء مجلّد باسم learnRuby أو أيّ اسم آخر لحفظ ملفّات روبي التي سنعمل عليها في هذه السلسلة، احفظ الملف باسم hello.rb أو أيّ اسم آخر مع وجوب إضافة rb. في آخره حيث rb. هو الامتداد المستخدم لكلّ سكربتات روبي. بعد حفظ الملفّ، افتح الطرفيّة واذهب إلى المجلّد الذي قمت بحفظ الملفّ به عن طريق كتابة الأمر التالي: cd [file path] حيث file path هو مسار الملفّ. مثلاً إذا قمت بحفظ الملفّ في مجلّد learnRuby في C على ويندوز فالمسار سيكون C:\learnRuby وبالتّالي سيكون الأمر: cd C:\learnRuby بعد التوجّه إلى المجلّد الذي يحتوي على الملفّ نقوم بتشغيل البرنامج، كل ما علينا فعله هو كتابة: ruby hello.rb بعد تنفيذ الأمر ستلاحظ ظهور النصّ المكتوب، نفس العمليّة التي قمنا بها في سطر أوامر روبي التفاعليّ. الفرق الوحيد بين كتابة روبي في ملف وبين كتابتها في سطر أوامر روبي التفاعليّ هو أن سطر أوامر روبي التفاعليّ ينفّذ أمر روبي في كل مرّة نضغط Enter. أمّا كتابة شيفرات روبي في ملفّات يسمح لك بكتابة أكثر من سطر أوامر والتي ستُنفّذّ جميعًا عند تشغيل البرنامج. يمكننا التحقُّق من ذلك بالعودة إلى الملفّ المستخدم وإضافة أوامر أخرى. مثلاً، جرّب الأوامر التالية أسفل الأمر الموجود في الملفّ: puts 1 + 1 3.times do puts "Ruby" end احفظ الملف، وأعد تشغيله كما فعلت من قبل، ماذا تلاحظ؟ بمجرّد الضغط على Enter نحصل على نتيجة تنفيذ جميع الشيفرات البرمجيّة مرّة واحدة. التعليقات في روبي مع زيادة حجم الشيفرات البرمجيّة وتعقيدها، سيصبح من الصعوبة قراءتها وفهمها. لهذا السبب فمن المفيد إضافة ملاحظات إلى برنامجك لتوضيح وظيفة أجزاء البرنامج لك ولأي مبرمج آخر سيقرأ هذه الشيفرات فيما بعد. تسمّى تلك الملاحظات تعليقات. تبدأ التعليقات في روبي برمز التلبيد Hash (#) وكل ما يأتي بعد هذا الرمز يتمّ تجاهله ولا يُنفّذ. جرّب كتابة تعليق في ملفّ hello.rb وأعد تشغيل البرنامج. تحقّق هل حدث اختلاف في النتائج أم لا. مثال على تعليق: # هذا البرنامج يطبع حاصل ضرب الرقمين 3 * 4 puts 3 * 4 ختام تعرّفنا في هذا الدّرس على مدى بساطة روبي وقربها من الإنجليزيّة العاديّة، ما يميّزها عن لغات البرمجة الأخرى وكيف يمكن تنصيب وبدء البرمجة باستخدامها. كذلك تعرّفنا على بعض المفاهيم الخاصّة باللّغة والتي إن لم تفهمها فلا تقلق، ليس من المفترض أن تعرف كلّ هذا حيث أنّنا سنستعرض هذا كلّه باستفاضة في الدروس القادمة من هذه السلسلة. إذا استعصى عليك أمر أو واجهت مشكلة، لا تتردد في السؤال عنها في قسم التعليقات أدناه. *مصدر المعلومات: ويكيبيديا.
  10. أسهل طريقة لتنفيذ أمر في روبي عدّة مرّات (في حالتك 5 مرّات) هي استخدام دالّة times: 5.times { send_sms_to("abc") } كذلك يمكنك استخدام دالّة upto: 1.upto(5) { send_sms_to("abc") } أو دالّة downto (تشبه upto، الاختلاف هو أنّها تبدأ بالقيمة الكبيرة وتبدأ بالعدّ تنازليًّا إلى القيمة الأصغر): 5.downto(1) { send_sms_to("abc") } الدوال الثلاث السابقة تعد بدائل فعّالة لحلقة For، يمكنك أيضًا استخدام For هكذا: for i in 1..5 { send_sms_to("abc") }بالتوفيق.
  11. أحيانًا تحتاج لعمل بعض التغييرات على موقع ووردبريس الخاص بك والتي تريد تجربتها أوّلاً قبل تثبيتها على موقعك، مثال على تلك التغييرات، تفعيل إضافات أو تغيير التصميم. هناك طريقة فعّالة لتنفيذ ذلك عن طريق عمل نسخة محليّة لموقعك من أجل الاختبار والتطوير. أو ربّما تريد البدء في العمل على موقع آخر ولكن بدلاً من تنفيذ تطويراتك على خادوم، فإنّك تريد إنشاء موقع تطوير على حاسوبك الشخصي من أجل تجربة ما تقوم بعمله أوّلاً. لا يقوم ذلك بالإبقاء على موقعك مخفيًّا عن العالم فقط، بل سيقوم أيضًا بجعل عملية التطوير الخاصّة بك أسرع حيث أنّه لن تكون هناك حاجة إلى انتظار عمليّة رفع الملفّات كلّما أجريت بعض التغييرات. سأقوم في هذا المقال باستعراض كيفيّة تثبيت ووردبريس محليًّا (على حاسوبك بدلاً من الويب). سأشرح لك ذلك عن طريق خطوات مفصّلة مزوّدة بصور توضيحيّة. بعد انتهائك من القراءة وربّما التنفيذ لن تجد عمليّة تثبيت ووردبريس محلّيًّا بالأمر الشاق على الإطلاق. ستحتاج إلى اتّباع أربع خطوات: تثبيت MAMP على حاسوبك (يمكن لمستخدمي ويندوز الحصول على MAMP أيضًا، حيث أنّ البرنامج لم يعد مقتصرًا فقط لمستخدمي Mac كما كان في السابق). تفعيل خواديم MAMP المحليّة وتغيير إعدادات المنافذ (اختياري). إنشاء قاعدة بيانات على حاسوبك والتي بها سيتمّ تخزين محتوى موقعك (يتمّ عمل هذا عن طريق كتابة كلمة واحدة والضغط على زر واحد فقط). تثبيت ووردبريس عن طريقة عمليّة التثبيت الشهيرة التي تستغرق أقل من 5 دقائق. تثبيت MAMP ستحتاج أوّلاً تحميل برنامج MAMP .MAMP هو اختصار لـ Macintosh, Apache, MySQL and PHP. يشير هذا الاسم إلى أنّ البرنامج تمّ تطويره في بادئ الأمر للاستخدام على أجهزة Macintosh فقط ولكن حاليًا يمكن استخدام البرنامج على نظم تشغيل ويندوز ولينكس أيضًا ويعتبر البرنامج أسهل طريقة للعمل مع ووردبريس محليًّا. سبب حاجتك إلى MAMP هو أنّ البرنامج يستطيع تشغيل على جهازك كل من: PHP (اللغة البرمجة التي كُتب بها ووردبريس) قاعدة بيانات MySQL خادوم Apache يعني ذلك أنّه بإمكانك كتابة وتنفيذ استعلامات (Queries) من قاعدة البيانات التي يخزّن ووردبريس بها محتوى موقعك. اذهب إلى موقع MAMP، حمّل البرنامج مجّانًا وقم بتثبيته على حاسوبك. تفعيل الخواديم المحلية باستخدام MAMP الآن حيث أنّ لديك البرنامج مثبّتًا فإنّك تحتاج إلى بدء تشغيله وتشغيل الخواديم على جهازك. يعني هذا تعديل الإعدادات إلى أخد الخيارين التاليين: إبقاء خيار منفذ Apache كمان هو 8888 ممّا يعني أنّه كلّما أردت زيارة موقعك المحلّي ستحتاج إلى كتابة رقم المنفذ في متصفّحك. تغيير أرقام منفذ Apache إلى 80 والذي يعني أنّك لن تحتاج إلى كتابة رقم المنفذ في متصفّحك، ولكن في هذه الحالة سيحتاج منك MAMP كتابة كلمة مرور حاسوبك في كل مرّة يبدأ البرنامج العمل. لن يؤثّر اختيار أحد الخيارين على كيفيّة عمل MAMP أو عمل موقعك. الأمر مجرّد اختيار بين إذا ما كنت تريد كتابة 8888 في متصفّحك في كل مرّة تزور الموقع محلّيًّا، أم أنّك تفضّل كتابة كلمة المرور. بالنسبة لي فأنا أفضّل الخيار الثاني حيث أنّني سأحتاج إلى كتابة رقم المنفذ أكثر من كتابة كلمة المرور، لذلك فسأقوم بتفعيل الخيار الثاني. لتفعيل أحد الخيارين علينا أوّلاً تشغيل MAMP. تشغيل MAMP افتح برنامج MAMP مثلما تفتح أيّ برنامج آخر، ستجد نافذة البرنامج: يجب أن تكون الصناديق الصغيرة الموجودة بجانب Apache Server وMySQL Server مؤشّرة وأن تكون أيقونة التشغيل خضراء. إذا كان أحد الصناديق أو الصندوقين غير مؤشّرين أو أيقونة التشغيل لونها أحمر فعليك الضغط على رابط Start Servers (والذي ستجده على الجانب الأيمن من النّافذة، تمامًا في نفس موضع رابط Stop Servers الموجود في الصورة أعلاه). الآن إذا أردت إبقاء المنافذ على إعداداتها الافتراضيّة فيمكنك تخطّي الخطوة التالية. أمّا إذا أردت تغيير الإعدادات فتابع القراءة. تعديل إعدادات المنفذ (Port) لكي تتمكن من ضبط إعدادات المنفذ، اضغط على رابط Preferences لفتح نافذة التفضيلات، بعد ذلك اضغط على تبويب Ports الموجود بالأعلى: عدّل حقل Apache Port ليصبح 80 (مثلما هو موضّح بالصورة) ثم اضغط على زر OK. بعد فعل هذا ستتغيّر الإعدادات وسيتم توصيلك بكلمة مرور حاسوبك. الخطوة التالية (لا فرق إذا قمت بتغيير الإعدادات أم لا) هي إنشاء قاعدة بيانات لموقعك. إنشاء قاعدة بيانات اضغط على زر Open start page من نافذة MAMP الرئيسيّة. ستقوم صفحة بدء MAMP بالظهور على متصفّحك كما هو موضّح بالصورة التالية: لاحظ أن تلك الشاشة تعطيك بيانات عن إعدادات قاعدة بيانات MySQL الخاصّة بك والتي سوف تحتاجها لاحقًا عندما تبدأ في عمليّة تثبيت ووردبريس. لا تتحمّل عناء تذكّر تلك البيانات فسوف أقوم بتزويدك بها عند الوصول إلى خطوة التثبيت. الآن اضغط على تبويب phpMyAdmin بأعلى الصفحة أو على رابط phpMyAdmin الموجود في قسم MySQL. بعد الضغط على التبويب أو الرابط ستفتح لك وحدة phpMyAdmin. اضغط على تبويب Databases الموجود في أعلى صفحة phpMyAdmin لفتح شاشة قواعد البيانات: لاحظ أنّ لديّ فعلاً بعض قواعد البيانات جاهزة في استضافتي المحليّة والتي تظهر بشكل ضبابي في الصورة أعلاه. لن ترى قواعد البيانات هذه لديك حيث أنّ تثبيت MAMP لديك لا يزال جديدًا. لإنشاء قاعدة البيانات المطلوبة عليك كتابة اسم قاعدة البيانات في حقل Create database. يمكن تسمية قاعدة البيانات باسم WordPress إذا كنت تنوي تشغيل موقع واحد فقط محليًّا ولكن إذا كنت تخطط لتشغيل أكثر من موقع واحد محليًّا فمن المفيد أن تعطي قاعدة البيانات اسمًا يدلّ على كل موقع على حدة. من الأفضل تسمية قاعدة البيانات باسم أقصر من اسم موقعك، كذلك لا يمكنك تضمين مسافات أو تشكيل في اسم قاعدة البيانات. بعد انتهائك من كتابة اسم قاعدة البيانات اضغط على زر Create وبهذا سيتم إنشاء قاعدة بياناتك. هل توقّعت أن تكون عمليّة إنشاء قاعدة بيانات أكثر تعقيدًا من ذلك؟ لحسن الحظ هذا كل شيء. الآن لنبدأ بتثبيت ووردبريس. تثبيت ووردبريس الآن خطوة تثبيت ووردبريس. إذا قمت بتثبيت ووردبريس يدويًّا من قبل على خادوم بعيد فمؤكّد أنّك على دراية بهذه العمليّة. تابع القراءة إذا لم تقم بالتثبيت يدويًّا من قبل واعتمدت دائمًا على برامج التثبيت. تحميل ووردبريس ووضعه في مجلد MAMP بدايةً ستحتاج إلى الحصول على نسخة من ووردبريس. اذهب إلى صفحة تحميل ووردبريس بالعربيّة وقم بتحميل نسخة من الإصدار الأخير. بعد انتهاء عمليّة التحميل ستحصل على ملفّ مضغوط، قم بفك ضغط الملفّ وقم بنسخ المجلد الناتج عن فك الضغط بأكمله إلى مجلّد MAMP/htdocs: على جهاز Mac، ستجد هذه في مجلّد Applications، لذلك ستصبح ملفّات ووردبريس الخاصّة بك موجودة في Application/MAMP/htdocs/Wordpress. على نظام Windows، ستصبح ملفّات ووردبريس الخاصّة بك في C;\MAMP\htdocs\Wordpress. إذا كنت ستقوم بتشغيل أكثر من موقع محليًّا فعليك تغيير اسم مجلّد WordPress إلى اسم يدل على كل موقع على حدة، وتأكّد من عدم تضمين مسافات في الاسم. الآن وبعد تنفيذ ما تمّ ذكره، أنت جاهز للخوض في عمليّة التثبيت. عملية التثبيت افتح متصفّحك واكتب localhost/WordPress في حقل العنوان (URL) في أعلى الشاشة. إذا لم تقم بتغيير إعدادات منفذك فاكتب localhost:8888/wordpress في حقل العنوان. إذا قمت بتسمية المجلّد باسم آخر غير WordPress فاكتب اسم المجلّد الذي اخترته أيضًا. بعد كتابة العنوان صحيحًا في حقل العنوان سترى أوّل شاشات تثبيت ووردبريس والتي ستخبرك ببيانات قاعدة بياناتك التي ستحتاجها لتثبيت ووردبريس (لاحظ أنّه إذا قمت بتحميل نسخة ووردبريس غير العربيّة فقبل هذه الشاشة ستظهر لك شاشة أخرى تسألك عن اللغة التي تريد ووردبريس العمل بها): لا حاجة للقلق فسوف أعطيك هذه المعلومات، كلّ ما عليك فعله هو الضغط على زر ابدأ الآن! ستظهر لك الآن الشاشة التي ستقوم فيها بإدخال بيانات قاعدة البيانات الخاصّة بك: قم بإدخال البيانات التالية (والموجودة أيضًا في الصورة أعلاه): اسم قاعدة البيانات: WordPress (أو أي اسم آخر اخترته لقاعدة البيانات التي قمت بإنشائها) اسم المستخدم: root كلمة المرور: root اسم المستضيف: localhost بادئة الجدول: _wp ستجد أن أغلب هذه الحقول قد تمّ ملؤها بالإعدادات الصحيحة على كل حال. الآن اضغط على زر إرسال. الشاشة التاليّة هي مفضّلتي، تخبرك تلك الشاشة أنّ ووردبريس يتواصل مع قاعدة بياناتك وهي الخطوة الأهم على الإطلاق: اضغط على زر البدء بالتنصيب للذهاب إلى الخطوة التالية. بعد ذلك ستجد شاشة تسألك على بيانات موقعك: قم بكتابة البيانات الخاصّة بموقعك مثلما كنت تفعل عند تثبيت ووردبريس على استضافة الويب الخاصّة بك. سيقترح عليك ووردبريس استخدام كلمة مرور قويّة، إلّا أنّ هذا الأمر لا يُعدّ مشكلة عند العمل محليًّا. يمكنك أيضًا القيام بإلغاء تأشير صندوق الظهور لمحركات البحث، حيث أنّه لن يمكن لجوجل الوصول إلى موقعك المحلّي، ولكن تذكّر تغيير هذا الإعداد في شاشة التحكّم إذا قمت بنقل الموقع إلى استضافة بعيدة لاحقًا. قم أخيرًا بالضغط على تنصيب ووردبريس. الآن سترى شاشة تمّ بنجاح. اضغط على زرّ دخول للوصول إلى موقعك: قم الآن ببساطة بتسجيل الدخول إلى موقعك مثلما تفعل دائمًا. سيتمّ أخذك إلى لوحة تحكم ووردبريس الخاصّة بموقعك الجديد والتي من خلالها يمكنك إضافة محتوى، تثبيت إضافات وقوالب وفعل أيّ شيء آخر تتوقع فعله على موقع ووردبريس على الويب. انتهيت لتوّك من تثبيت ووردبريس بنجاح على حاسوبك. الآن يمكنك استخدامه لإنشاء بيئة تطوير موقع أو ربّما استيراد محتوى من موقعك الموجود على استضافة بعيدة واختبار التطويرات عليه قبل تفعيلها. ختام لحسن الحظّ فإنّه الآن بعد قراءتك لهذا المقال (وربّما اتبّاعك للخطوات الموجودة به) لن تجد مهمّة إنشاء موقع ووردبريس محلّيًّا عملاً شاقًّا. يجعل استخدام برنامج MAMP عمليّة تشغيل خواديم محليّة، إنشاء قاعدة بيانات ثم تثبيت ووردبريس عمليّة مباشرة. يمكنك الآن استخدام موقعك الجديد في تطوير أفكار جديدة أو اختبار إضافات وقوالب قبل استخدامها على موقعك على الانترنت. هل تستخدم ووردبريس محلّيًا أم أنّك كنت قلقًا من تجربة الأمر؟ هل أفادك هذا الدرس؟ يسرّنا استقبال رأيك في قسم التعليقات بالأسفل. ترجمة -وبتصرّف- للمقال How To Develop WordPress Locally with MAMP لصاحبته Rachel McCollin. اقرأ أيضًا دليلك المصور لتثبيت ووردبريس لمحة عن لوحة تحكم ووردبريس استخدام قوالب ووردبريس
  12. إذا كان لديك موقع تطوير، توثيق لمشروع، قسم مساعدة منتجات أو أي شيء مماثل وكنت تستعمل ووردبريس كنظام إدارة مُحتوى، فهناك احتمالات أنّك احتجت إلى عرض شيفرات برمجيّة في وقت أو آخر. قد يسبّب هذا الأمر مشكلة صغيرة أو مشكلة كبيرة جدًا على حسب لغة البرمجة المستخدمة. سنقوم في هذا المقال بتوضيح لماذا يعدّ هذا أمرًا مثيرًا للإزعاج وكذلك استكشاف بعض الخيارات المتاحة لك من أجل عرض الشيفرات البرمجيّة بشكلٍ جميل وسهل على موقع ووردبريس الخاص بك. لماذا عرض الشيفرات البرمجية أمر صعبتحتاج لفهم سبب صعوبة عرض الشيفرات البرمجيّة إلى معرفة بعض أساسيّات HTML. لجعل بعض النصوص عريضة (Bold) فعليك وضعها بين وسوم. من أجل جعل الخط عريضًا مثل هذا النصّ فسأحتاج إلى كتابة <strong>الخط عريضًا</strong> في محرّر ووردبريس الخاص بي. الأمور إلى الآن جيّدة ولكن الجزء الصعب هو: ماذا لو أردتُ أن أريك كيف قمتُ بعمل ذلك؟ في أيّ وقت أقوم بكتابة <strong> في المحرّر سيتمّ ترجمتها كشيفرة HTML برمجيّة، يعني هذا أن الوسم سوف يختفي وفي المقابل سيتم إظهار النص عريضًا. المشكلة الأخرى الموجودة لدينا هي إبراز بنية الجملة (Syntax) وتلوينها. حتى إذا تمّ عرض الشيفرات البرمجيّة بشكل صحيح فربّما يكون من الصعب قراءتها بدون التنسيق الصحيح. عرض الشيفرات البرمجيةأفضل طريقة لعرض الشيفرات البرمجيّة بالشكل الصحيح هي تحويل الرموز ذات المعاني المميّزة إلى HTML Entities (كيانات HTML). ربّما تكون على درايّة أنّه أحيانًا قد تحتاج إلى كتابة &amp; بدلاً من علامة العطف & العاديّة لجعلها تظهر على نحوٍ صحيح. يرجع هذا إلى أنّ &amp; هي كيان HTML الخاص بعلامة العطف &. لا يتمّ ترجمة كيانات HTML إلى شيفرات برمجيّة وإنّما يتم عرضها مثل نظيراتها من غير الكيانات. من أجل أن تريني كيف تنشئ خطّ عريض فعليك أن تكتب شيء يشبه ما يلي: &lt;strong&gt;bold text&lt;/bold&gt;&lt; هي كيان HTML لعلامة أقل من (لاحظ اختصار lt) و&gt; كيان HTML لعلامة أكبر من، لهذا استخدمنا الاختصار gt. إضافة شيفرة برمجية إلى تدوينة ووردبريس – الطريقة السهلةأسهل طريقة لإضافة شيفرات برمجيّة إلى تدويناتك هي أن تستخدم كيانات HTML وتحيط كل شيء بوسم <pre>. مثال سريع لتوضيح الأمر: <pre> add_action('admin_notices', 'show_mot_text'); function show_mot_text() { $text = get_motivation_text(); echo "&lt;p id='wp-admin-motivation'&gt;$text&lt;/p&gt;"; } </pre>لاحظ كيف قمتُ بإدراج الشيفرات البرمجيّة بعد وسم <pre> مباشرةً وأغلقتُ الوسم باستخدام <pre/> بعد آخر رمز في الشيفرة البرمجيّة. قد ترى أنّه من الأفضل لو تمّ وضع الوسوم في أسطر منفردة ولكن في هذه الحالة ستقوم خاصيّة إبراز بنية الجملة (Syntax Highlighter) في جافا سكربت بترجمة فواصل الأسطر تلك على أنّها فواصل أسطر فعليّة. ولذلك فعدم ترك فواصل أسطر تعتبر عادة حميدة هنا. تعمل هذه الطريقة بشكل جيّد ولكن صيانتها تعتبر كابوسًا. إذا كان لديك العديد من الوسوم وليس فقط النصّ الوحيد الموجود في المثال ستجد هناك فوضى من كيانات HTML مما يجعل عمليّة تعديل الشيفرات البرمجيّة أمرًا صعبًا. إذا احتجتُ إلى اللجوء إلى هذه الطريقة فإنّني أستخدم محرّر نصوصي لإنشاء كيانات HTML. أقوم بكتابة شيفرات برمجيّة عاديّة ومن ثمّ تحويل كل كيانات HTML مرّة واحدة باستخدام محرّر النصوص. إذا احتجت إلى تعديل الشيفرات البرمجيّة فيمكنك لصق النسخة المحوّلة ثمّ فكّ ترميز الكيانات إلى الرموز الصحيحة. إذا كنت تستخدم Atom.io فيمكنك استخدام حزمة HTML Entities، أمّا إذا كنت تستخدم محرّر النصوص Sublime فيمكنك استخدام أمر HTML: Encode Special Characters. رغم أنّه باستطاعتك الحصول على سير عمل جيّد باستخدام هذه الطريقة، إلا أنّ الشيفرات البرمجيّة تظهر بشكل مضطرب في محرّر تدوينات ووردبريس ودعونا نعترف أنّ هذه النتيجة أبعد ما تكون عن نظام سير عمل سريع. طريقة أفضل لعرض الشيفرات البرمجيةطريقة أفضل لإضافة شيفرات برمجيّة إلى موقع هي استخدام إضافة لتنفيذ هذا الأمر بالتحديد. الكثير من الإضافات تستخدم مكوّن جافا سكربت يعمل على إبراز بنية الجملة وخيارات أخرى لشيفراتك البرمجيّة. مكوّن إبراز بنية الجملة المفضّل بالنسبة لي هو Prism ولحسن الحظّ هناك إضافة تقوم بدمجه في ووردبريس. حمّل إضافة Prism WP، ثبّتها ثم ابدأ في كتابة شيفراتك البرمجيّة مع اتّباع التعليمات التالية. قم بإحاطة شيفراتك البرمجيّة باستخدام وسم <pre> ووسم <code>.قد تتم إضافة فئة معيّنة class إلى هذا الوسم والتي ستحدّد اللغة المستهدفة، وذلك لإبراز وتلوين الشيفرة بشكل مُناسب.إذا أردت إضافة ترقيم للأسطر فستحتاج إلى تفعيل هذا من إعدادات الإضافة ثم تضيف فئة line-numbers إلى وسم <pre>.مثال الشيفرة البرمجيّة السابق يبدو كما يلي الآن في المحرّر: <pre class="line-numbers"> <code class='language-php'> add_action('admin_notices', 'show_mot_text'); function show_mot_text() { $text = get_motivation_text(); echo "<p id='wp-admin-motivation'>$text</p>"; } </code> </pre>يبدو هذا أفضل بكثير، أليس كذلك؟ الإخراج الخاص بهذه الشيفرات لطيف أيضًا، تلقائيًّا سيظهر الإخراج مثل الصورة أدناه في حالة استخدام قالب Twenty Fifteen. هناك عدد آخر من القوالب التي يمكنك استخدامها، ربّما تريد إلقاء نظرة على الصفحة الرئيسيّة لإضافة Prism. يمكن تغيير القوالب بالنّقر على الدّوائر الموجودة في الجانب الأيمن. تتيح لك الإضافة تغيير القالب من خلال الإعدادات الخاصّة بالإضافة. خدمات خارجيةهناك عدد كبير جدًا من الخدمات التي تسمح لك بلصق شيفراتك البرمجيّة مثل Gist ،JSFiddle و Pastebin. لدى كل خدمة من هذه الخدمات إضافات ووردبريس تمكنك من تضمين شيفراتك في تدوينات ووردبريس الخاصّة بك. أقترح عليك الذهاب إلى صفحة البحث عن الإضافات في ووردبريس والبحث عن الإضافة المناسبة لك، ستجد العديد منها في ثوانٍ معدودة. افعلها بنفسك DIYأفضّل دائمًا الاعتماد على نفسي لإيجاد حلول للمشاكل عملاً بمبدأ افعلها بنفسك (DIY – Do It Yourself)، لذلك دعونا نحاول حل هذه المشكلة دون اللجوء لحلول جاهزة. لن نتطرّق لعمليّة الإبراز لأنّها صعبة للغاية، ولكن باستطاعتنا فعل الكثير لجعل إضافة الشيفرات البرمجية في ووردبريس أكثر سهولة. أكبر مشكلة تواجهنا هي مشكلة كيانات HTML. ما نريد فعله هو القدرة على كتابة الشيفرات البرمجيّة كما هي في الواجهة الخلفيّة (Backend) وعرضها كما هي أيضًا في الواجهة الأماميّة (Frontend) بدون ترجمة الوسوم. يمكن تنفيذ ذلك عن طريق إضافة مرشّح (Filter) إلى the_content. الفكرة عبارة عن أنّه قبل عرض المحتوى سنبحث خلال هذا المحتوى عن أي نصوص بين وسوم code واستبدال أي رموز مميّزة بها بكيانات HTML. لقد قمتُ قبل بضعة أشهر بكتابة إضافة بسيطة تسمّى Smart Code Escape لفعل هذا الأمر. الإضافة مثال ممتاز على شيء مفيد يستخدم 15 سطر شيفرات برمجيّة فقط. لنلق نظرة الآن. أول شيء تحتاج لفعله هو إنشاء إضافة. يمكن الاطلاع على سلسلة "مدخل إلى برمجة إضافات ووردبريس" إذا لم يكن لديك معرفة مسبقة حول كيفيّة برمجة الإضافات. باختصار: قم بإنشاء مجلّد في مجلّد الإضافات الخاصّ بك وقم بتسميته smart-code-escape وبداخل المجلّد قم بإنشاء ملفّ باسم smart-code-escape.php. قم بإضافة المحتوى التالي إلى الملف. <?php /* * Plugin Name: Smart Code Escape * Plugin URI: https://github.com/danielpataki/Smart-Code-Escape * Description: Converts less than, greater than and ampersand characters to their HTML entities within pre tags before they are output on the page. You will always see the non-escaped version in the editor, making code easy to modify. It Will not convert code tags directly within pre tags to support Prism-style highlighting. * Version: 1.1 * Author: Daniel Pataki * Author URI: http://danielpataki.com * License: GPL v2 * Licence URI: http://www.gnu.org/licenses/gpl-2.0.txt */ function smart_code_escape_pre($data) { preg_match('@(<code.*>)(.*)(<\/code>)@isU', $data[2], $matches); if(!empty( $matches)) { return $data[1] . $matches[1] . str_replace(array('&', '<', '>'), array('&amp;', '&lt;', '&gt;'), $matches[2]) . $matches[3] . $data[3]; } else { return $data[1] . str_replace(array('&', '<', '>'), array('&amp;', '&lt;', '&gt;'), $data[2]) . $data[3]; } } add_filter('the_content', 'smart_code_escape_content', 9); function smart_code_escape_content($content) { $content = preg_replace_callback('@(<pre.*>)(.*)(<\/pre>)@isU', 'smart_code_escape_pre', $content); return $content; }تحتوي الإضافة الأصليّة على توثيق مضمّن للشيفرات البرمجيّة، إذا كنت مهتمًّا فيمكنك تحميلها من المستودع وإلقاء نظرة عليها. أوّل شيء يمكن ملاحظته هو أنّني قمتُ بإضافة مرشّح إلى the_content. يقوم هذا المرشّح باستدعاء دالّة Callback تعمل مع المحتوى الموجود بين وسوم <pre>. تقوم دالة ()smart_code_escape_pre بتولي عمليّة التحويل. تعمل أوّلاً على التحقّق ممّا إذا كانت الشيفرات البرمجيّة محاطة بوسم <code>. فكّرتُ في عمل هذا التحقّق للتأكّد من أنّ الإضافة لن تتعارض مع إضافات الشيفرات البرمجيّة الأخرى مثل إضافة Prism السابق ذكرها. أتوقّع أنّه إذا قام أحدهم بإضافة شيفراتهم البرمجيّة عن طريقة إحاطتها بوسم <pre> وكذلك وسم <code> فمؤكّد أنّه يريد بالفعل عرض الشيفرات البرمجيّة كما هي في تدوينته وليس تنفيذ الشيفرات وإظهار تأثيرها على النص فقط. إذا لم تكن محتويات الوسم <pre> موجودة داخل وسم <code> فستقوم الدّالة باستبدال كل الرموز المميّزة بكيانات HTML المعبّرة عنها. خاتمةكما تلاحظ فإنّ إضافة شيفرات برمجيّة إلى موقعك ليس بالأمر الصعب، كل ما عليك معرفته مجرّد أساسيّات لماذا يتم فك الترميز. ترجمة -وبتصرّف- للمقال: How To Display Code On Your WordPress Website The Proper Way لصاحبه Daniel Pataki.
  13. تلعب جداول التسعير دورًا هامًّا في مساعدة زوّار موقعك في رؤية ومقارنة مختلف المميّزات التي تقدّمها خططك التسعيريّة. تكمن المشكلة في أنه يمكن لهذه الجداول أن تشكّل تحديًا من ناحية التصميم وسهولة الاستخدام في ذات الوقت. يجب أن تكون الجداول بسيطة ولكن يجب أن تفرّق بشكل واضح بين ميزات وأسعار الخدمات والمنتجات المختلفة. إذا لم يتمكّن مستخدموك من رؤية قيمة المنتج أو الخدمة فورًا فعليك أن تعرف أن أموالهم لن تُغادر محافظهم. ولكن يمكن لجداول مقارنة التسعير -مع بعض استراتيجيّات التسويق الصحيحة- توفير وسيلة فعّالة لتحديد موضع إظهار حِزَمك من أجل زيادة المبيعات. لذلك سنقوم بإلقاء نظرة على أفضل الإضافات المتاحة لمساعدتك في إظهار تسعيرك بالطريقة الصحيحة في موقعك المبني باستخدام ووردبريس. CSS3 Responsive Pricing Table إضافة CSS3 Responsive Pricing Table المُقدّمة من طرف QuanticaLabs هي إضافة جداول تسعير لووردبريس مدفوعة والتي توفر تصميمًا متجاوبًا. إذا كان مجرّد التفكير في احتياجك لكتابة شيفرات برمجيّة يسبب لك التوتر فإن هذه الإضافة طُوّرت خصيّصا لك. الإضافة متوافقة مع ووردبريس متعدّد المواقع أيضًا (Multisite WordPress). هناك تصميمان يمكنك الاختيار من بينهما، فاتح وغامق، وكل تصميم يأتي مع 20 لون مُختلف. تم تطوير الإضافة باستخدام CSS3 فقط مما يجعل الإضافة صغيرة الحجم ومؤثّرة. قام المطورون أيضًا بإطلاق نسخة HTML من الإضافة. تأتي الإضافة مُحمّلة بخيارات عديدة مثل ضابط وضع التجاوب ولوحة إدارة شاملة مع ضبط حي live configuration. لديك إمكانيّة التحكم الكامل في تصميم الجدول باستخدام عدد كبير من الخيارات للصفوف، الأعمدة، حالات الحومان (Hover states)، الأشرطة وأيقونات صح/خطأ (tick/cross icons). يمكنك الحصول على ترخيص عادي مقابل 18 دولار والذي يقدم لك أيضًا 6 أشهر دعم من المطورين والتحديثات المستقبليّة. خصائص الإضافةتفعيل وضع التجاوب وتحديد خطوات وأبعاد التجاوبلوحة إدارة بديهيّة مع ضبط حيتصميمان للجدول، 20 لون مُختلفعدد لا نهائي من الجداولعدد لا نهائي من الأعمدة والصفوفإظهار/إخفاء عمود أو عدّة أعمدة من لوحة الإدارةتحديد الأعمدة كنشطة (مُنبثقة)صفوف قابلة للتوسيعحالات الحومان (Hover states)42 أيقونة صح/خطأمثال حييستخدم موقع Fast Followerz هذه الإضافة منذ ثلاث أعوام إلى الآن. الصورة التالية توضح معاينة لجدول التسعير المصمم لشركتهم القائم على تقديم خدمات على الإنترنت. لاحظ كيفية انبثاق الأعمدة وإذا قمت بزيارة الموقع باستخدام هاتف ذكي ستلاحظ أن التصميم متجاوب. Plugmatter Pro Pricing Table Plugin إضافة Plugmatter Pro Pricing Table Plugin هي إضافة ووردبريس مدفوعة سهلة الاستخدام والتي تساعدك على إنشاء جداول مقارنة أسعار عالية التحويل. وفقًا لموقع الإضافة فإنه "يمكن للإضافة حرفيًّا أخذ مبيعاتك إلى المرحلة التالية وكذلك جعل تصميم موقعك متكاملاً". خاصيّة تحسين التحويل الموجودة بالإضافة مدعومة بواسطة دراسات البحث السلوكي وتحسين مُعدّل التحويل (CRO)، والتي تعطي الإضافة ميزة تنافسيّة تسبق جداول التسعير الأخرى من وجهة نظر تسويقيّة. تمّ تصميم الإضافة لأولئك الذين لا يريدون كتابة شيفرات برمجيّة. تحصل مع هذه الإضافة على 10 قوالب جداول تسعير متجاوبة ومُخصّصة والتي صُمّمت خصّيصًا لزيادة مُعدّل التحويل لموقعك. من الناحية التصميميّة، فإنه يُمكن للقوالب أن تظهر بصورة قوالب مصفوفة أو قوالب بطاقات. هُناك ثلاث خطط يُمكنك الاختيار من بينها بالنسبة لهذه الإضافة. أقلها سعرًا هي 47 دولار. إلا أنّ الخدمات التقنية عالية الجودة المُقدّمة بواسطة الإضافة تُبرّر أسعارها العالية. خصائص الإضافةمُحرّر مرئي WYSIWYGإمكانيّة ترتيب الصفوف والأعمدة بطريقة السحب والإفلات (Drag and Drop)خطوط جوجل وأيقونات Font Awesomeتعقّب الأحداث من جوجل23 زر قابلة للتعديلمُحرّر الخلايا مُحمّل مع خيارات مُختلفةتصميم متجاوب بالكاملاختبار A/B Split Testingدعم فوري للمُستخدمينرموز قصيرة (Short Codes)يُمكن تجربة جميع القوالب باستخدام مُدخلات واحدةVisual Composer Pricing Table Add-On إضافة Viusal Composer Pricing Table Add-On هي إضافة متجاوبة والتي تم تصميمها خصّيصًا للقوالب التي تم إنشاؤها باستخدام Visual Composer. الميزة البارزة لهذه الإضافة هي أّنّها تُتيح لك حريّة تخصيص خلفيّة، ألوان الخط والشفافيّة (Transparency) بالنسبة لجدول التسعير. مما يُعني أنّه لن تكون بحاجة للتعامل مع مجموعة من القوالب المُعرّفة مسبقًا من جديد. تم تصميم جداول التسعير بطريقة تجعلها تلعب دور أزرار الدّعوة إلى الإجراء Call to action. ستحصل مع الإضافة على أيقونات Font Awesome لإضافة المزيد من الحيويّة لجدول التسعير الخاص بك. تحتوي الإضافة على خاصيّة التبديل (toggle) والتي تُتيح إمكانيّة تبديل مقدار المساحة بين الخطط المختلفة في جدولك. ثمن الترخيص العادي هو 17 دولار والذي يشتمل على ستّة أشهر من الدّعم الفنّي. خصائص الإضافةتخطيطات عمود مُخصّصةتنسيقات حدود (borders) مُخصّصةخلفيّة وألوان خط مُخصّصة بالكاملتأثيرات شفافيّةأيقونات Font Awesomeإضافة تأثيرات تحريكالتّحكّم في المسافات بين خطط التسعيرصناديق الدعوة إلى الإجراءمثال حييستخدم موقع College for Pets هذه الإضافة لعرض أسعار الشهادات التي يقدمونها. Easy Pricing Table إضافة Easy Pricing Table التي توفّرها Fatcat Apps هي جداول تسعير مشهورة يسهل إعدادها خلال دقيقتين فقط. تُقدّم الإضافة 10 قوالب لجداول تسعير متجاوبة تمامًا والتي تحتوي على تلميحات مُضمّنة تُمكّنك من عرض معلومات مُفصّلة عن منتجك أو خدمتك دون بعثرتها. وفقًا لموقع الإضافة، فإن الإضافة ستعمل فور قيامك بتثبيتها. فلا تحتاج لكتابة شيفرات برمجيّة لأي شيء أو الخوض في إعدادات ضبط مُعقّدة. ستكون الإضافة مُثبّتة لديك وتعمل في دقائق معدودة. تُقدّم الإضافة أيضًا خطط خاصة بالشّركات والوكالات والتي تحتوي على تبديلات التسعير وإضافات إحصائيّات جوجل. تبديلات التسعير تُتيح لعملائك معاينة معدّلات التسعير التي تضعها لخدمة معيّنة بعملات مختلفة أو لفترات مختلفة (على سبيل المثال، خطط فصليّة، خطط سنويّة، إلى آخره). تُقدّم Fatcat Apps فترة 60 يوم لاستعادة مبلغك إذا لم تكن راضيًا عن جداول التسعير المُقدّمة. يُمكنك الحصول على ترخيص شخصي مقابل مبلغ 29 دولار والذي يمكن استخدامه في موقع واحد. بهذا الترخيص ستحصل على 10 قوالب ودعم عب البريد الإلكتروني. خصائص الإضافة10 قوالب تصميممتجاوبة وقابلة للتخصيص بالكاملسهلة الاستخدامتلميحات مضمّنةدعم بريد إلكتروني مدفوعإضافة تبديل الأسعارإضافة إحصائيات جوجلمثال حيربمّا تكون قد رأيت جداول Easy Pricing Tables في العديد من المواقع ولكنّك لم تعرف أنّها هي نفس الإضافة. إليك بعض المواقع الشهيرة التي تستخدم الإضافة لأغراضها التجارية: WooThemes، Social Media Examiner، Pagely، WPBeginner، WP Mayor، WPLift و wpmudev. PricingTable إضافة Pricing Table التي تطوّرها ParaTheme هي إضافة جدول تسعير ووردبريس مجّانيّة وصغيرة الحجم. تقوم الإضافة بإنتاج نظام HTML/CSS شبكي (grid) خالص لعرض الجدول في موقعك. إنّ سهولة استخدام الإضافة، تصميمها المتجاوب ومجموعة أخرى من المميزات هي أمور تجعل من هذه الإضافة خيارًا شائعًا لمن لا يريد شراء جدول تسعير. يُمكن ببساطة سحب وإفلات صفوف/أعمدة وإدارة جدول التسعير من خلال لوحة الإدارة المدمجة الخاصّة بالإضافة. تتضمّن الإضافة خاصيّة دعم الرموز القصيرة والتي تُمكّن المستخدمين من وضع جدول التسعير أينما أرادوا بسهولة. أحد أفضل الخصائص بهذه الإضافة هي أنّه بإمكانك تضمين فيديو (يوتيوب أو فيميو) في خطط جدولك التسعيري. خصائص الإضافةمتجاوبةعدد لا نهائي من الأعمدة والصفوفخاصّية السحب والإفلاتحزمة من 7 ألوان للنصوصحزمة من 12 لون للخلفية19 شريط للأعمدة21 خط من خطوط جوجلتدعم الإضافة وضع صورة خلفية في منطقة الجدولGo Pricing – WordPress Responsive Pricing Table تدعم إضافة Go Pricing – WordPress Responsive Pricing Table المُقدّمة بواسطة Granth العديد من عناصر الوسائط شاملة صور، خرائط، تسجيلات صوتيّة وفيديو. تثبيت الإضافة يستغرق بضع دقائق مع لوحة الإدارة. مدمج بالإضافة أيقونات Font Awesome، Icomoon، Linecon وMateral. كلها أيقونات يمكنك استخدامها في جدولك التسعيري المُخصّص. يمكنك معاينة الشكل النهائي لجدول التسعير الخاص بك قبل نشره على موقع وذلك باستخدام خاصيّة المعاينة الفوريّة التي توفّرها الإضافة. توفّر هذه الإضافة الكثير من الوقت الذي يمكن أن يُستنفذ في النشر ثم العودة لإضافة تعديلات بسيطة. تحتوي الإضافة على أكثر من 250 تصميم قالب يمكنك الاختيار منها. القوالب قابلة للتخصيص بالكامل مما يعني أنّه بإمكانك فعل أي شيء مثل تغيير مساحة الخلايا أو تعيين ألوان مختلفة لكل عمود. الترخيص العادي متاح مقابل 20 دولار والذي يسمح لك باستخدام الإضافة في موقع واحد فقط. خصائص الإضافةمجموعة من أكثر من 250 قالب جاهزأكثر من 650 خط من خطوط جوجلأكثر من 1900 أيقونة خطوطعدد لا نهائي من الأزرارتوفير QR Codeمعاينة فوريّة للجداولتخطيط متجاوبرمز قصير لزرّ باي بالعدد لا نهائي من الألوانمثال حييستخدم موقع View from the Boundary الإضافة لعرض خدمات الموقع التسويقيّة. ARPrice ARPrice هي إضافة مدفوعة تُطوّرها Repute InfoSystems. الإضافة تُقدّم جداول مقارنة تسعير متجاوبة وتتميز أيضًا بقوالب متحرّكة مع إمكانيّة تخصيصها. تأتي الحزمة وبها مجموعة فيها أكثر من 170 خيار لجداول التسعير يمكنك الاختيار من بينها. إذا لم تجد أيّ من تلك الجداول يناسب تصميم موقعك فيمكنك تخصيص الجدول بنفسك. مضمّن بالإضافة لوحة إدارة كاملة المزايا والتي من خلالها يمكن سحب وإفلات الأعمدة ومن ثمّ تغيير حجمها. يمكنك إضافة صور، خرائط جوجل، ملفّات صوتيّة وفيديوهات إلى جدول التسعير الخاص بك وإلحاق تأثيرات تحريك بهم. الترخيص العادي متاح مقابل 18 دولار والذي يحتوي على 6 أشهر دعم فنّي والتحديثات المستقبليّة. خصائص الإضافةأكثر من 170 قالب جداول تسعيرتأثيرات حركيةلوحة إدارة كاملة المزاياإمكانيّة السحب والإفلاتتجاوب مُخصّصخطوط جوجل وأيقونات Font Awesome مضمّنةدعم لسكربت بايبالإمكانيّة إضافة صور، خرائط، ملفّات صوتية، فيديودعم التلميحاتKento Pricing Tables تعدّ إضافة Kento Pricing Tables التي تطوّرها KentoThemes إضافة سهلة الاستخدام وقابلة للتخصيص مقدّمة لمواقع ووردبريس. تقوم الإضافة بإنتاج جداول تسعير تمّ إنشاؤها بواسطة HTML/CSS فقط والذي يعني أنها لن تتسبّب في بطء موقعك. تسمح لك الإضافة تخصيص أعمدة وصفوف الجدول بالكامل بالشكل الذي يتناسب مع قالب موقعك والألوان الموجودة به. تتيح لك الإضافة كذلك إمكانيّة تحديد اللون الرئيسي للجدول بلون من اختيارك. ولمن أصابه الملل من الألوان البسيطة فإنّه يمكن إضافة صورة خلفية إلى الجدول. يجب مراعاة أنّ صورة الخلفيّة ليست متجاوبة فلا تتوقع أن تعمل بسلاسة في الهواتف الذكية. تعديل حجم الصفوف والأعمدة بسيط. كل ما عليك فعله هو إدخال القيم وسوف تحصل على جدول بنفس الأبعاد المُحدّدة. خصائص الإضافةتصميم متجاوبعرض مُخصّص للأعمدةعدد لا نهائي من الأعمدة والصفوفلوحة إدارة سهلة الاستخدامحقول إظهار/إخفاء فارغةمثال حييستخدم موقع WebPrezence.com الإضافة في متجره الإلكتروني. يمكن أن ترى كيف أضافت صورة الخلفيّة التي استخدموها تأثيرًا مُكمّلاً للمظهر العام لجدول التسعير. POWr Price Table إضافة POWr Price Table التي تقدّمها POWr هي إضافة مجّانيّة مُختلف عن غيرها، حيث أنها خدمة سحابية ممّا يعني أنّه بإمكانك تعديل موقعك حتى بعد نشره. كما تدعم الإضافة خدمة بايبال ممّا سيُسهّل على زبائنك عملية الدّفع. تُتيح لك الإضافة إنشاء أنظمة دفع دوري لأشياء مثل العضويّات أو الاشتراكات. هذه الميزة ليست موجودة بالإضافات الأخرى التي تمّ استعراضها من قبل. يمكن في هذه الإضافة تخصيص الألوان، الخطوط والخلفيّات. يمكنك استخدام خاصيّة الإبراز (Highlight) لجعل خطّة معيّنة تبرز بين باقي الخطط الأخرى. كما تدعم الإضافة لغات مختلفة ومتجاوبة بالكامل. خصائص الإضافةمتجاوبة بالكاملخدمة سحابيةدعم مدمج للنصوص للعديد من اللغاتإمكانيّة إنشاء خاصيّة الدفع الدوريخاصيّة الإبراز لجعل خطّة محدّدة بارزة عن الخطط الأخرىخطوط، خلفيّات وألوان مُخصّصةدعم بايبالمقارنة بين إضافات جداول التسعير اختيار الإضافة الأنسب من الجدول أعلاه قد تكون مهمّة صعبة حيث أنه يوجد على الأقل ميزة واحدة تبرز كل إضافة عن الإضافات الأخرى. إذا كنت تبحث عن إضافة جداول تسعير مدفوعة فإنّ إضافة Easy Pricing Tables ببساطة هي خيارك الأمثل. تمتلك الإضافة كل ما تحتاج إليه أن يكون موجودًا في إضافة جدول تسعير. أعجبتني خاصيّة تبديل التسعير، وهي الخاصيّة التي لا تقدّمها الإضافات الأخرى. تصبح خاصيّة تبديل التسعير إلزاميّة عندما تختلف أسعار منتجك أو خدمتك. تحتوي إضافة POWr Price Table على العديد من المميّزات التي لا توجد بالإضافات الأخرى. مثل دعم اللّغات المختلفة وكونها خدمة سحابية. إذا كنت تقوم بتغيير المظهر العام لموقعك كثيرًا، فعلى الأرجح أفضل خيار لك هو جداول التسعير التي توفّرها إضافة GO Pricing حيث أن هناك أكثر من 250 خيار يمكنك الاختيار من بينها. اختيار أفضل إضافة تسعيرهناك عدد كبير جدًا من حلول جداول التسعير لووردبريس، ولكن تم اختيار هذه الإضافات التسعة بناءً على خصائصها الممتازة وقدرتها على الموازنة بين التصميم وقابلية الاستخدام. رأينا كيف قامت مواقع حقيقيّة بتنفيذ جداول التسعير الخاصّة بهم عن طريق استخدام الخصائص الأكثر أهميّة بالنسبة لهم. الآن لديك معرفة جيّدة بمختلف جداول التسعير الموجودة وماذا يمكن لكل إضافة من الإضافات تقديمه لك. إذا كنت تريد إضافة بها مجموعة من قوالب الجداول المصمّمة مسبقًا للاختيار من بينها أو واحد تقوم بتخصيصه بنفسك، فإنّك الآن لديك بعض الخيارات المختلفة التي بإمكانك الاختيار منها. هل تستخدم جداول التسعير في موقعك؟ ما هي أفضل إضافة جدول تسعير بالنسبة لك؟ قم بإخبارنا في قسم التعليقات بالأسفل. ترجمة -وبتصرّف- للمقال Nine Best Pricing Table Plugins For WordPress لصاحبه Tom Ewer.
  14. أحيانًا قد يحتاج قالب أو إضافة إلى إظهار إشعارات/تنبيهات للمُستخدمين عبر لوحة تحكُّم ووردبريس. تنفيذ هذا الأمر بسيط جدًّا حيثُ أنَّهُ يتمّ باستخدام خُطَّاف admin_notices والذي يقوم باظهار صُندوق رسائل في أعلى الشَّاشة. عرض إشعار قياسيfunction my_admin_notice(){ echo '<div class="updated"> <p>I am a little yellow notice.</p> </div>'; } add_action('admin_notices', 'my_admin_notice');حيثُ أنَّه قد تمَّ إضافة الصّنف"updated" إلى الوسم div فسيظهر الإشعار باللَّون الأصفر. أمَّا في حالة تغيير الصّنف إلى "error" فإنَّ الإشعار يظهر أحمرًا. كيفيَّة عمل إشعار قابل للإغلاقمن المُمكن -مع القليل من العمل الإضافي- عرض الإشعار وإبقائه حتَّى يقوم المُستخدم بالضغط على زرٍّ لإغلاقه. تُعتبر تلك الطَّريقة مُفيدة للتأكُّد من أنَّ المُستخدم قد قام برؤية الإشعار وكذلك لن يُضايقه وجود الإشعار طوال الوقت. المثال التَّالي تمَّ استخراجه من إضافة AddThis. يُستخدم أيضًا شيء مُشابه في Options Framework.. إذا قام المُستخدم بالضَّغط لإخفاء الإشعار فسيتمّ حفظ تفضيله في بيانات user meta. /* Display a notice that can be dismissed */ add_action('admin_notices', 'example_admin_notice'); function example_admin_notice() { global $current_user ; $user_id = $current_user->ID; /* Check that the user hasn't already clicked to ignore the message */ if ( ! get_user_meta($user_id, 'example_ignore_notice') ) { echo '<div class="updated"><p>'; printf(__('This is an annoying nag message. Why do people make these? | <a href="%1$s">Hide Notice</a>'), '?example_nag_ignore=0'); echo "</p></div>"; } } add_action('admin_init', 'example_nag_ignore'); function example_nag_ignore() { global $current_user; $user_id = $current_user->ID; /* If user clicks to ignore the notice, add that to their user meta */ if ( isset($_GET['example_nag_ignore']) && '0' == $_GET['example_nag_ignore'] ) { add_user_meta($user_id, 'example_ignore_notice', 'true', true); } }عرض الإشعارات في صفحات تحكُّم مُعيَّنةأحيانًا قد نحتاج إلى تحديد ظهور الإشعار ليكون في صفحاتٍ مُعيَّنة قد يحتاج المُستخدم لرؤية الإشعار بها. يُمكنكَ تنفيذ هذا باستخدام المُتغيِّر العام $pagenow. على سبيل المثال، سيظهر الإشعار التالي في صفحة الإضافات فقط: function my_admin_notice(){ global $pagenow; if ( $pagenow == 'plugins.php' ) { echo '<div class="updated"> <p>This notice only appears on the plugins page.</p> </div>'; } } add_action('admin_notices', 'my_admin_notice');التحقُّق من دور المُستخدم قبل عرض الإشعاريجب عرض الإشعارات للمُستخدمين المعنيين بالأمر فقط. على سبيل المثال، لا فائدة من عرض إشعار عن تعديل خيارات القالب لمُستخدم لا يملك صلاحية التَّعديل على خيارات القالب. إليكَ طريقة للتّحقق من الأدوار الشائعة: if ( current_user_can( 'install_plugins' ) ) if ( current_user_can( 'manage_options' ) ) if ( current_user_can( 'edit_theme_options' ) )آداب الإشعارأحيانًا تُصبح الإشعارات مُزعجة، لهذا عليكَ الحذر عند استخدامها. أبقِ النَّصَّ قصيرًا وحاول ألَّا تعرض أكثر من إشعار. عليك استخدام هذه الميزة باعتدال. مصادر أخرىhttp://theme.it/how-to-display-an-admin-notice-for-required-theme-pluginshttp://codex.wordpress.org/Plugin_API/Action_Reference/admin_noticesترجمة -وبتصرّف- للمقال: Admin Notices in WordPress.
  15. يعتبر React.js -على حداثته- من أقوى أطر عمل Javascript (بعضهم قد يسميه مكتبة وليس إطار عمل) لبناء الواجهات الرسومية على الويب، حيث طبّق أفكارًا جديدة في هذا المجال، جعلت شِفرة الواجهات البرمجية أكثر نظافة، سرعة وأكثر قابلية للصيانة. يسمح لك React ببناء الواجهة الرسومية في مجموعة مكونات، كل مكوّن عبارة عن سرد لهيكلة ومنطق المكون، إذا تمزج بين شِفرة HTML مخصصّة وشِفرة جافاسكربت تصف سلوك ذاك المكون، ليكون قائما بذاته وقابلا لإعادة الاستعمال. إطار عمل React مُطور من طرف شركة فيس بوك (Facebook)، وقد يكفيك ثقة ويجذب انتباهك بمجرد أن تعرف أن فيس بوك نفسها تستخدم React في واجهتها البرمجية على موقع Facebook نفسه! يمكنك فتح موقع Facebook وعرض شفرة HTML الخاصة به والبحث عن كلمة react للتأكد بنفسك. سنقوم في هذا الدرس بإنشاء مُربَّع تعليقات بسيط وفعَّال بإمكانك وضعه في مدوَّنتك، سيكون المُربَّع عبارة عن نُسخة مُجرَّدة من التعليقات الآنية التي تُقدمها لك تعليقات Disquse ،LiveFyre أو فيس بوك. ستجد في نهاية الدَّرس أنَّ لديكَ مُربَّع تعليقات يوفِّر ما يلي: عرض لجميع التعليقات.نموذج لإرسال تعليق.خُطَّافات لتوفير مُنتهى خلفي مُخصَّص custom backend.سوف يحتوي مُربَّع التعليقات كذلك على بعض المزايا اللَّطيفة: تعليق مُحسَّن: تظهر التَّعليقات في القائمة قبل أن يتمّ حفظها على الخادم وبناءً عليه تظهر التَّعليقات في التوِّ واللَّحظة.تحديثات حيَّة: تظهر تعليقات المستخدمين الآخرين في عرض التَّعليقات في نفس وقت الإرسال.هيئة Markdown: يُمكن للمستخدمين استخدام Markdown لتهيئة نصوصهم.هل ترغب في تخطِّي كل هذا ومعاينة المصدر؟ كل شيء موجود على GitHub. تشغيل الخادمرغم أنَّه ليس من الضروري أن تبدأ بهذا الجزء من الدرس إلَّا أنَّنا سنقوم في وقت لاحق بإضافة وظائف تتطلَّب المُشاركة POST إلى خادم قيد التشغيل. إذا كُنتَ واثقٌ من أنّك على دراية بهذا الأمر وترغب في إنشاء خادمك الخاص يُمكنكَ القيام بذلك. ولِمَن يُريد التَّركيز على تعلُّم React دون الحاجة إلى القلق بشأن جوانب الخادم، فلقد كتبنا خوادم بسيطة بعددٍ من اللُّغات: Python ،Ruby ،Go، Node.js و PHP. كلُّ هذا مُتاح على GitHub. يُمكن الاطِّلاع على المصدر أو تحميل ملفّ مضغوط للبدء. للبدء بتطبيق هذا الدَّرس، كلّ ما عليكَ فعله هو بداية تحرير public/index.php. البدءسنستخدم لهذا الدرس ملفَّات JavaScript سبق إنشاؤها على شبكة توصيل مُحتوى CDN. قم بفتح المُحرِّر المفضَّل لديك وقم بإنشاء مُستند HTML جديد: <!-- index.html --> <!DOCTYPE html> <html> <head> <title>Hello React</title> <script src="https://fb.me/react-0.13.3.js"></script> <script src="https://fb.me/JSXTransformer-0.13.3.js"></script> <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script> </head> <body> <div id="content"></div> <script type="text/jsx"> // Your code here </script> </body> </html>سيتمّ كتابة شفرات JavaScript في وسم السكربت هذا طوال الفترة المتبقية من الدرس. مُلاحظة: قُمنا بإدراج jQuery هُنا لأننا نٌريد تبسيط الشَّفرات لاستدعاءات Ajax في المُستقبل، ولكنَّها ليست إلزاميَّة لعمل React. مُكوِّنكَ الأوَّلتتمحور الفكرة الأساسيَّة لـ React حول كل شيءٍ له علاقة بالمُكوِّنات التركيبيَّة القابلة للتَّشكيل modular, composable components. سنستخدم بنية المُكوٍّنات التالية لمثال مُربَّع التَّعليقات لهذا الدرس: - CommentBox - CommentList - Comment - CommentFormسنقوم الآن ببناء المُكوِّن CommentBox وما هو إلَّا وسم بسيط: // tutorial1.js var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> Hello, world! I am a CommentBox. </div> ); } }); React.render( <CommentBox />, document.getElementById('content') );لاحظ أن أسماء عناصر HTML تبدأ بحرف صغير في حين أن أسماء فئات React تبدأ بحرف كبير. 1. صياغة JSXستُلاحظ أوَّل ما تلاحظ تلكَ الصياغة المُشابهة لـ XML في شفرة JavaScript. لدينا precompiler بسيط يُترجم الجُملة البسيطة Syntactic Sugar إلى شفرات JavaScript المُجرَّدة هذه: // tutorial1-raw.js var CommentBox = React.createClass({displayName: 'CommentBox', render: function() { return ( React.createElement('div', {className: "commentBox"}, "Hello, world! I am a CommentBox." ) ); } }); React.render( React.createElement(CommentBox, null), document.getElementById('content') );إنَّ استخدام صياغة JSX اختياري ولكن وجدنا أنَّها أسهل استخدامًا من شفرات JavaScript مُجرَّدة. يُمكن قراءة المزيد في مقال صياغة JSX 2. ماذا يحدث هنانقوم بتمرير بعض الوظائف في كائن JavaScript إلى دالَّة ()React.createClass لإنشاء مُكوِّن React جديد. أهم هذه الوظائف ما تُسمَّى تصيير render والتي تُعيد شجرة من مُكوِّنات React والتي في نهاية المطاف ستقوم بالتصيير عبر HTML. لا تُعتبر وسوم عُقَد نموذج كائن مُستند DOM فعليَّة، وإنَّما هي تمثيلات من مُكوِّنات div الخاصَّة بـ React. يُمكنكَ اعتبارها كوسوم أو قطع من البيانات والتي يعرف React كيفيَّة التعامل معها. React آمن. لا نقوم بتوليد سلاسل HTML لذلك فإن حماية XSS تُعتبر الافتراضيَّة. لا يجب عليكَ إعادة شفرات HTML قياسيَّة. وإنَّما يُمكنكَ إعادة شجرة من المُكوِّنات التي قُمتَ (أو شخص آخر قام) ببنائها. هذا ما يجعل React قابلة للتَّشكيل composable: وهي عقيدة أساسيَّة في الواجهات الأماميَّة القابلة للصّيانة. يقوم ()React.render بتمثيل المُكوِّن القاعدي، بدء عمل الإطار، ثم إدخال الوسوم إلى عنصر نموذج كائن مُستند خام، يتمّ تقديم تلك الوسوم كمُعطى ثاني . تركيب المُكوِّناتسنُنشيء الآن هياكل بناء لكلٍّ من المُكوِّنين CommentList وCommentForm والتي ستكون -مرَّة أخرى- عبارة عن وسوم بسيطة. أضِف هذين المُكوِّنين إلى ملفِّك مع الحفاظ على تعريف commentBox الحالي واستدعاء React.render: // tutorial2.js var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> Hello, world! I am a CommentList. </div> ); } }); var CommentForm = React.createClass({ render: function() { return ( <div className="commentForm"> Hello, world! I am a CommentForm. </div> ); } });ما سنقوم بعمله الآن هو تحديث مُكوِّن CommentBox لاستخدام المُكوِّنات الجديدة: // tutorial3.js var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList /> <CommentForm /> </div> ); } });لاحظ كيف تمَّ مزج وسوم HTML والمُكوِّنات التي قُمنا ببنائها. إنَّ مُكوِّنات HTML ما هي إلَّا مُكوِّنات React مُنتظمة، تمامًا مثل تلك التي تقوم بتعريفها ولكن مع فارق واحد. سيقوم مترجم JSX تلقائيًا بإعادة كتابة وسوم HTML إلى تعبيرات React.createElement() tagName وترك كل شيء على حدة. وهذا لمنع حدوث التَّلوّث في مساحة الاسم العموميَّة global namespace. استخدام الخصائصسنقوم الآن بانشاء مُكوِّن Comment، والذي سوف يعتمد على البيانات التي تمَّ تمريرها إليه من المُكوِّن الأساسي. يتمّ اتاحة البيانات التي تمّ تمريرها من مُكوِّن أساسي كـ "خاصيَّة" في المُكوِّن الفرعي. ويتمّ الوصول إلى هذه "الخصائص" من خلال this.props. يُمكننا باستخدام الخصائص props قراءة البيانات التي تمّ تمريرها إلى Comment من CommentList، وتصيير بعض الترميزات: // tutorial4.js var Comment = React.createClass({ render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> {this.props.children} </div> ); } });يُمكنكَ وضع نصّ أو مُكوِّنات React في الشَّجرة وذلك بإحاطة تعبير JavaScript بأقواس داخل JSX (إما كخاصيَّة أو كمُكوِّن فرعي). نقوم بالوصول إلى خاصيَّات مُسمَّاه تمّ تمريرها إلى عنصر كمفاتيح على this.props وأيّ عناصر مُتداخلة كما this.props.children. خصائص المُكوِّننحتاج الآن وبعد أن قمنا بتحديد مُكوِّن Comment إلى تمرير اسم الكاتب ونصّ التعليق إلى هذا المُكوِّن. يسمح لنا هذا بإعادة استخدام نفس الشَّفرة لكلِّ تعليق مُختلف. لنقوم الآن بإضافة بعض التَّعليقات داخل مُكوِّن CommentList: // tutorial5.js var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> <Comment author="Pete Hunt">This is one comment</Comment> <Comment author="Jordan Walke">This is *another* comment</Comment> </div> ); } });لاحظ أنَّنا قد قُمنا بتمرير بعض البيانات من مُكوِّن CommentList الأساسي إلى مُكوِّنات Comment الفرعيَّة. مرَّرنا على سبيل المثال Pete Hunt (عن طريق خاصيَّة) وThis is one comment (عن طريق عُقدة فرعيَّة تُشبه XML) إلى Comment الأوَّل. وكما ذكرنا بالأعلى فإنَّ مُكوِّن Comment سيعمل على الوصول إلى هذه الخصائص من خلال this.props.author، وthis.props.children. إضافة MarkdownMarkdown هي طريقة بسيطة لتهيئة مُضمّنة inline لنصِّك. على سبيل المثال، احاطة النص بعلامة النجمة (*) سيقوم بتأكيده. أولًا، أضِف مكتبة الطرف الثالث marked إلى تطبيقك. Marked هي مكتبة JavaScript تقوم بأخذ نص Markdown وتُحوِّله إلى صيغة HTML خام. هذا الأمر يتطلَّب وسم سكربت في قسم head (قُمنا بادراجه بالفعل في أرضيَّة React): <!-- index.html --> <head> <title>Hello React</title> <script src="https://fb.me/react-0.13.3.js"></script> <script src="https://fb.me/JSXTransformer-0.13.3.js"></script> <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script> </head>سنقوم بعد ذلك بتحويل نصّ التَّعليق إلى Markdown ومن ثمَّ إخراجه: // tutorial6.js var Comment = React.createClass({ render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> {marked(this.props.children.toString())} </div> ); } });كل ما فعلناه هنا هو استدعاء مكتبة marked. نحتاج إلى تحويل this.props.children من نصّ React مُحاط إلى سلسلة خام يُمكن لمكتبة marked فهمها ولذلك فإننا نقوم بستدعاء دالَّة ()toString. لكن لدينا مشكلة وهي أنَّه يتمّ إظهار وسوم HTML الموجودة في التَّعليقات بالشكل التَّالي في المُتصفح: This is another comment. هذا الأمر هو حماية React لك من هجوم XSS. هُناك طريقة للالتفاف على ذلك، ولكنَّ إطار العمل يُحذِّرُكَ من استخدامها: // tutorial7.js var Comment = React.createClass({ render: function() { var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML={{__html: rawMarkup}} /> </div> ); } });هذه الشَّفرات هي API خاصّ والذي عمدًا يجعل من الصَّعب إدراج شفرات HTML خام، في حالتنا بالنِّسبة لمكتبة marked فإنَّنا سنقوم بالاستفادة من هذا المنفذ الخلفيّ. تذكَّر: باستخدامك لهذه الميزة فإنَّك تعتمد على مكتبة marked أن تكون آمنة. نقوم في هذه الحالة بتمرير sanitize: true التي تطلب من مكتبة marked تنفيذ أي وسم HTML في المصدر بدلًا من تمريره دون تغيير. إضافة نموذج البياناتحتَّى الآن فإنَّنا نقوم بإدراج تعليقات مُباشرة في شفرات المصدر. بدلًا من ذلك، سنقوم بتصيير بضع من بيانات JSON في قائمة التعليق. يأتي هذا من الخادم في نهاية المطاف، ولكن في الوقت الراهن سنكتبها نحن في المصدر: // tutorial8.js var data = [ {author: "Pete Hunt", text: "This is one comment"}, {author: "Jordan Walke", text: "This is *another* comment"} ];الآن نحنُ بحاجة إلى إدخال هذه البيانات في مُكوِّن CommentList بطريقة نموذجيِّة. قُم بتعديل CommentBox واستدعاء ()React.render لتمرير هذه البيانات إلى CommentList عن طريق الخصائص props: // tutorial9.js var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.props.data} /> <CommentForm /> </div> ); } }); React.render( <CommentBox data={data} />, document.getElementById('content') );الآن حيثُ أنَّ البيانات مُتاحة في CommentList، سوف نقوم بتقديم التَّعليقات بطريقة ديناميكيَّة: // tutorial10.js var CommentList = React.createClass({ render: function() { var commentNodes = this.props.data.map(function (comment) { return ( <Comment author={comment.author}> {comment.text} </Comment> ); }); return ( <div className="commentList"> {commentNodes} </div> ); } });هذا كل شيء. الاستدعاء من الخادمسنعمل الآن على استبدال البيانات الثَّابتة ببعض البيانات الديناميكيَّة من الخادم. يتمّ ذلك بإزالة خاصيَّة البيانات data prop واستبدالها بعنوان URL للجلب: // tutorial11.js React.render( <CommentBox url="comments.json" />, document.getElementById('content') );هذا المُكوِّن مُختلف عن المُكوِّنات السَّابقة حيثُ أنَّه سيضطر إلى إعادة تصيير نفسه. لن يحتوي المُكوِّن على أيّ بيانات إلى أن يعود الطَّلب من الخادم، في هذه الحالة قد يحتاج المُكوِّن إلى تصيير بعض التَّعليقات الجديدة. الحالة التفاعليَّةقام كلّ مُكوِّن حتَّى الآن على أساس خصائصه بتصيير نفسه مرة واحدة. الخصائص props ثابتة: يتمّ تمريرها من المُكوِّن الأساسي و”مملوكة” من قبل المُكوِّن الأساسي كذلك. لتنفيذ التَّفاعلات، فإنَّنا نُقدِّم حالة قابلة للتغيير إلى المُكوِّن. حالة this.state هي خاصَّة بالمُكوِّن ويُمكن تغييرها من خلال استدعاء ()this.setState يقوم المُكوِّن بإعادة تقديم نفسه عند تحديث الحالة. وظائف ()render مكتوبة إلزاميًّا كدوال this.props وthis.state. يضمن إطار العمل أن تكون واجهة المستخدم دائمًا مُتَّسِقَة مع المُدخَلات. عندما يقوم الخادم بجلب بيانات سنقوم نحن بتغيير بيانات التعليق لدينا. لنُضيف الآن مصفوفة من بيانات التَّعليق كحالة للمُكوِّن CommentBox: // tutorial12.js var CommentBox = React.createClass({ getInitialState: function() { return {data: []}; }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } });يتمّ تنفيذ دالَّة ()getInitialState مرَّة واحدة فقط خلال دورة حياة المُكوِّن كما أنَّها تبدأ الحالة الأوليَّة للمُكوِّن. تحديث الحالةنُريد عند إنشاء المُكوِّن لأوَّل مرَّة أن نحصل على (GET) بعض بيانات JSON من الخادم وتحديث الحالة لتعكس أحدث البيانات. هذا من شأنه أن يكون نقطة نهاية ديناميكيَّة لو كان الأمر في تطبيق حقيقي، ولكن سنستخدم لهذا المثال ملف JSON ثابت لابقاء الأمور بسيطة: // tutorial13.json [ {"author": "Pete Hunt", "text": "This is one comment"}, {"author": "Jordan Walke", "text": "This is *another* comment"} ]سنقوم باستخدام مكتبة jQuery للمساعدة في عمل طلب غير متزامن asynchronous request إلى الخادم. مُلاحظة: حيثُ أنَّ هذا الأمر أصبح تطبيق AJAX فإنَّك سوف تحتاج لتطوير تطيبقك باستخدام خادم ويب بدلًا من أن ملف موجود في نظام ملفاتك. قدَّمنا -كما هو مذكورٌ بالأعلى- العديد من الخوادم التي يُمكنكَ استخدامها على GitHub. توفر تلك الخوادم التأدية الوظيفيَّة التي تحتاجها لبقيَّة هذا الدرس. // tutorial13.js var CommentBox = React.createClass({ getInitialState: function() { return {data: []}; }, componentDidMount: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } });وظيفة componentDidMount هنا هي وظيفة تُستدعى تلقائيًا بواسطة React عندما يتمّ تصيير مُكوِّن. مفتاح التَّحديثات الديناميكيَّة هو استدعاء دالَّة ()this.setState. نقوم باستبدال مصفوفة التَّعليقات القديمة بواحدة جديدة من الخادم وتقوم واجهة المستخدم بتحديث نفسها تلقائيًا. بسبب هذا التفاعل، يُعتبر التغيير لإضافة تحديثات حيَّة طفيفًا. سوف نستخدم أسلوب بسيط في هذا الدَّرس ولكن لكَ الحُريَّة في استخدام WebSockets أو غيرها من التكنولوجيَّات. // tutorial14.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } }); React.render( <CommentBox url="comments.json" pollInterval={2000} />, document.getElementById('content') );كل ما فعلناه هنا هو نقل استدعاء AJAX إلى وظيفة مُستقلَّة واستدعائها عند تحميل المُكوِّن الأوَّل واستدعائها كلّ ثانيتين بعد ذلك. حاول تشغيل هذا في مُتصفِّحك وتغيير ملف comments.json. في غضون ثانيتين ستظهر لكَ التغييرات. إضافة تعليقات جديدةحان الآن الوقت لبناء النموذج. على مُكوِّن CommentForm أن يسأل المُستخدم عن اسمه ونصّ التَّعليق، ثم يقوم بإرسال طلب إلى الخادم لحفظ التعليق. // tutorial15.js var CommentForm = React.createClass({ render: function() { return ( <form className="commentForm"> <input type="text" placeholder="Your name" /> <input type="text" placeholder="Say something..." /> <input type="submit" value="Post" /> </form> ); } });دعونا نجعل النموذج متجاوب. عندما يقوم المُستخدم بإرسال النَّموذج، يجب علينا مسحه clear، تقديم طلب إلى الخادم، ثُمَّ تحديث قائمة التعليقات. للبدء في تنفيذ هذا، سقوم بالاستماع إلى حدث ارسال النَّموذج ومسحه. // tutorial16.js var CommentForm = React.createClass({ handleSubmit: function(e) { e.preventDefault(); var author = React.findDOMNode(this.refs.author).value.trim(); var text = React.findDOMNode(this.refs.text).value.trim(); if (!text || !author) { return; } // TODO: send request to the server React.findDOMNode(this.refs.author).value = ''; React.findDOMNode(this.refs.text).value = ''; return; }, render: function() { return ( <form className="commentForm" onSubmit={this.handleSubmit}> <input type="text" placeholder="Your name" ref="author" /> <input type="text" placeholder="Say something..." ref="text" /> <input type="submit" value="Post" /> </form> ); } });1- الأحداث Eventsتقوم React بإرفاق مُعالجات الحدث في المُكوِّنات باستخدام اتفاقية التَّسمية camelCase. نقوم بإرفاق مُعالج onSubmit إلى النَّموذج الذي يعمل على مسح حقول النَّموذج عند إرساله مع إدخال صحيح. عليكَ استدعاء ()preventDefault بالحدث لمنع الإجراء الافتراضي للمُتصفِّح من اعتماد النَّموذج. 2- المراجع Refsنستخدم خاصيَّة ref لتعيين اسم للمُكوِّن الفرعي وthis.refs لارجاع المُكوِّن. يمكن أن نستدعي (React.findDOMNode(componentعلى مُكوّن للحصول على عنصر نموذج كائن مُستند المُتصفِّح الأصلي. 3- نداءات الخصائصعندما يُرسِل المُستخدم التَّعليق، فإنَّنا سوف تحتاج إلى تحديث قائمة التَّعليقات لتشمل التَّعليق الجديد. من الطبيعي أن تفعل كل هذا في مُكوِّن CommentBox حيث أنَّ المُكوِّن يمتلك الحالة التي تُمثِّل قائمة التَّعليقات. نحن بحاجة لتمرير البيانات من نُسخة المُكوِّن الفرعي الاحتياطيَّة إلى المُكوِّن. يتمّ فعل هذا في وظيفة render الخاصَّة بالأب عن طريق تمرير رد نداء جديد (handleCommentSubmit) في الابن ثُمَّ الزامها لحدث الابن onCommentSubmit. كُلَّما تم تشغيل الحدث، سيُنفَّذ الاستدعاء: // tutorial17.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, handleCommentSubmit: function(comment) { // TODO: submit to the server and refresh the list }, getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> </div> ); } });سوف نستدعي الآن النِّداء من CommentForm عندما يقوم المُستخدم بإرسال النَّموذج: // tutorial18.js var CommentForm = React.createClass({ handleSubmit: function(e) { e.preventDefault(); var author = React.findDOMNode(this.refs.author).value.trim(); var text = React.findDOMNode(this.refs.text).value.trim(); if (!text || !author) { return; } this.props.onCommentSubmit({author: author, text: text}); React.findDOMNode(this.refs.author).value = ''; React.findDOMNode(this.refs.text).value = ''; return; }, render: function() { return ( <form className="commentForm" onSubmit={this.handleSubmit}> <input type="text" placeholder="Your name" ref="author" /> <input type="text" placeholder="Say something..." ref="text" /> <input type="submit" value="Post" /> </form> ); } });الآن وبعد أن أصبح النِّداء في مكانه الصحيح، كل ما علينا القيام به هو الإرسال إلى الخادم وتحديث القائمة: // tutorial19.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, handleCommentSubmit: function(comment) { $.ajax({ url: this.props.url, dataType: 'json', type: 'POST', data: comment, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> </div> ); } });تحديثات مُحسَّنةمشروعنا الآن كامل الوظائف ولكن من المُمل أن نقوم بانتظار الطَّلب حتَّى يكتمل قبل ظهور تعليقك في القائمة. يُمكننا إضافة هذا التَّعليق إلى القائمة لجعل التطبيق يعمل بشكلٍ أسرع. // tutorial20.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, handleCommentSubmit: function(comment) { var comments = this.state.data; var newComments = comments.concat([comment]); this.setState({data: newComments}); $.ajax({ url: this.props.url, dataType: 'json', type: 'POST', data: comment, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> </div> ); } });ختامًاانتهيتَ لتوك من إنشاء مربع تعليقات في بضع خطوات بسيطة. يُمكنك الآن التَّعرُّف على المزيد حول أسباب استخدام React، أو الخوض في مراجع API وبدء العمل. ترجمة -وبتصرّف- للمقال: Tutorial | React.
  16. بغضِّ النَّظر عن ماهية موقع الوِّيب خاصَّتك، إلَّا أنَّكَ إذا أضفتَ إليه عرض شرائح JavaScript يؤدِّي كُلَّ وظائفه بجودةٍ عالية، فإنَّكَ بذلك تكون قد قُمتَ بتضييق الفجوة بين عملك والعُملاء المُستهدفين. لقد خَدَمَتْ عروض شرائح JavaScript على نحوٍ كبيرٍ كإضافاتٍ لصفحات الوِّيب، حيثُ أنَّها وسيلة رائعة لعرض الكثير والكثير من المعلومات في مساحةٍ صغيرةٍ نسبيًّا. إذا كانت التَّفاصيل المذكورة هذه كافية لإغرائكَ لإنشاء عرض شرائحكَ الخاص باستخدام JavaScript (مع اللَّوحات المُنزلقة) فأنتَ في المكان المُناسب لتعلُّم هذا. سنتشاركُ في هذا الدَّرس بعض الخطوات البسيطة التي يسهل تنفيذها لإنشاء عرض شرائح JavaScript. توضيح الخطوات المُتَّبعة في هذا الدَّرس لإنشاء عرض شرائح JavaScript سأستخدم في هذا الدَّرس شفرات HTML وCSS بسيطة لإنشاء مظهر عرض الشَّرائح في حين أنَّ تنفيذ وظيفة الإنزلاق سيتمّ عن طريق استخدام مكتبة jQuery وهي مكتبة تابعة لـ JavaScript. كما سأستخدم أيضًا إضافتين واسعتي الانتشار: LocalScroll وScrollTo لتقديم التَّاثيرأت الكامنة في عرض شرائح JavaScript. تسمحُ الإضافة الأولى للرَّابط بتخطِّي عرض الشَّرائح إلى شريحةٍ مُحدَّدة بناءً على المُعرِّف ID الذي قد تمَّ تحديده. بينما تُقدِّم الإضافة الثَّانية وظائف انزلاقٍ مُمتازة، حيثُ أنَّها توفِّر خاصيَّة الانتقال بين الشَّرائح بدلًا من القفز من شريحة إلى الأُخرى. حيثُ أنَّنا سنأخذ مُعامِلات الوصول الأساسيَّة في الحُسبان عند بناء عرض الشَّرائح، فسيكون بإمكان كُلّ مُستخدم التنقُّل وعرض الشَّرائح حتى عند توقُّف JavaScript عن العمل. فيما يلي نظرة على بنية HTML لعرض الشَّرائح: <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Sliding-enabled slideshow using jQuery | Script Tutorials</title> <meta name="description" content="Sliding-enabled slideshow using jQuery demo - Script Tutorials"> <!-- include to stylesheet --> <link rel="stylesheet" href="css/style.css" type="text/css" /> <!-- include jQuery library and other javascripts --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="js/jquery.scrollTo.js"></script> <script src="js/jquery.localscroll.js"></script> <script src="js/custom-scripts.js"></script> </head> <body> <div id="slideshow"> <!-- List of slider images --> <ul> <li id="slide1"><img src="images/slide1.jpg" alt="Slide 1" /></li> <li id="slide2"><img src="images/slide2.jpg" alt="Slide 2" /></li> <li id="slide3"><img src="images/slide3.jpg" alt="Slide 3" /></li> <li id="slide4"><img src="images/slide4.jpg" alt="Slide 4" /></li> <li id="slide5"><img src="images/slide5.jpg" alt="Slide 5" /></li> </ul> </div> <div id="slideshow-nav"> <!-- Navigation list of slider images --> <ul> <li><a href="#slide1">Slide 1</a></li> <li><a href="#slide2">Slide 2</a></li> <li><a href="#slide3">Slide 3</a></li> <li><a href="#slide4">Slide 4</a></li> <li><a href="#slide5">Slide 5</a></li> </ul> </div> </body> </html> بالاطّلاع بعنايةٍ على الشَّفرات أعلاه ستُلاحظ أنَّ شفرات HTML لصفحات العرض تبدأ بـ Doctype، عنوان title ورابط إلى ملف نمط CSS. بعد هؤلاء الثلاث ستجد أنَّه لتجهيز عرض الشَّرائح وتشغيله قد تمَّ اضافة رابط لكلٍّ من: الإضافتين LocalScroll وScrollTo السَّابق توضيحهما، مكتبة jQuery وملف script.js. كذلك قد تمَّ فصل شفرات HTML المسئولة عن تكوين عرض الشَّرائح إلى قسمين: وسم div مُعرَّف بـ slideshow وآخر مُعرَّف بـ slideshow-nav. من المُهمّ هُنا مُلاحظة أنَّ وسم div المُعرَّف بـ slideshow سوف يحتوي على قائمة غير مُرقَّمة من صورٍ مُتَّصلة، ووسوم li تحتوي على مُعرِّفاتٍ تتوافق مع روابط slideshow-nav. لنُلقي الآن نظرة على أنماط CSS css/style.css #slideshow {/*slider container css*/ width: 800px; height: 400px; overflow: hidden; margin: 50px auto 50px auto; box-shadow: 0px 0px 50px #333; -moz-box-shadow: 0px 0px 50px #333; -webkit-box-shadow: 0px 0px 50px #333; } #slideshow ul {/*manage slider scroll elements css*/ width: 4000px; list-style: none; } #slideshow ul li { float: left; } ستقوم أنماط CSS الموجودة بالأعلى بالعمل على تحويل المظهر البسيط النَّاشئ عن شفرات HTML إلى صفحاتٍ تظهرُ بشكلٍ يُشبه عرض الشَّرائح المطلوب. يتمّ تنفيذ هذا بدءًا من تحديد ارتفاع وعرض هذه الشَّرائح، تحديد أيضًا الأبعاد لتكون مُماثلة تمامًا لأبعاد شرائح الصور. مع كُلّ الشَّرائح عائمة جنبًا إلى جنب فإنَّه من المُمكن تحديد قياسات العرض الكُلِّي للقائمة الغير مُرقَّمة حتَّى 4590px. كذلك قد تمَّ استخدام خاصيَّة الفائض overflow لمنع ظهور الصور المُتعدِّدة بأكملها في الصَّفحة. كُلّ ما تحتاج لفعله هُنا هو ببساطة تعيين خاصيَّة الفائض كـ overflow: scroll، يؤدِّي هذا التَّعيين إلى السَّماح لعرض الشَّرائح بالعمل حتَّى في حالة عدم وجود JavaScript. تمَّ إضافة ظلّ لطيف باستخدام CSS3-box shadow كما هو مُبيَّن أدناه #slideshow-nav {/* Slider navigation container css */ width: 150px; margin: 0 auto 100px auto; } #slideshow-nav ul { list-style: none; } #slideshow-nav ul li { float: left; } #slideshow-nav ul li a {/* navigation styling css */ display: block; width: 20px; height: 20px; float: left; margin: 0 5px; background: #fff; text-indent: -9999px; border-radius: 50%; -webkit-border-radius: 50%; box-shadow: 0px 0px 30px #000; -webkit-box-shadow: 0px 0px 30px #000; } #slideshow-nav ul li a:hover, #slideshow-nav ul li a.active { /* hover and active navigation css */ background: #333; } بمُعاينةٍ دقيقةٍ هُنا سنُلاحظ أنَّه قد تمَّ نقل وسم div الذي تمَّ تعريفه بـ slideshow-nav إلى موضعٍ أسفل القسم الرئيسي لعرض الشَّرائح. لا نُريد كذلك وجود عدَّة أزرار في عرض الشَّرائح والتي لا تعمل عند تفعيل وظائف JavaScript. يُمكنكَ استخدام visibility: hidden لإخفاء تلك الأزرار كوضعٍ افتراضي، مِمَّا يجعل امكانية إظهارها في وقتٍ لاحق أمرًا مُتاحًا. قد يُثير اهتمامكَ أيضًا معرفة أنَّهُ قد تمَّ تحويل الروابط الخاصَّة بكلّ قائمةِ تنقُّلٍ إلى أزرار دائريَّة بمُساعدة border-radius في CSS3 مع إزاحة النَّصّ الافتراضي خارج الشَّاشة عن طريق تعيين قيمة سالبة لـ text-indent. إلى الآن فإنَّ عرض الشَّرائح يعمل بصورة ملموسة ودون الحاجة إلى JavaScript. هُناك فقط شريط تنقُّل يُتيح للمُستخدم التَّحرُّك ذهابًا وإيابًا بين صُورٍ مُختلفة. وأخيرًا، لنُلقي نظرة على وظائف jQuery js/custom-scripts.js $(document).ready(function() { var slider = $("#slideshow"); var slider_nav = $("#slideshow-nav"); slider_nav.find("a[href=#slide1]").addClass("active"); slider_nav.localScroll({ target:'#slideshow', axis: 'x' }); slider_nav.find("a").click(function(){ slider_nav.find("a").removeClass("active"); $(this).addClass("active"); }); }); إذا نظرتَ إلى الشَّفرات أعلاه ستجد أنَّه قم تمَّ تغيير أنماط CSS الخاصَّة بوسم slideshow من overflow: scroll إلى overflow: hidden لإزالة شريط التَّمرير. بعد ذلك تمَّ تعيين ظهور أزرار nav لتُصبح مرئيَّة مع اضافة فئة active تلقائيًّا إلى الزرّ الأوَّل. كذلك تمَّ تفعيل كلتا الإضافتين: LocalScroll وScrollTo، إضافةً إلى تطبيق وظائف LocalScroll على عناصر slideshow-nav عن طريق توجيه تلك العناصر لاستهداف عناصر slideshow بالتَّحرُّك على طول محور X. أخيرًا، للتأكُّد من أنَّ جميع الأزرار في عرض الشَّرائح تعمل مع فئتها النَّشطة (متى تمَّ نقرُها)، سوف نستخدم قاعدة jQuery بسيطة والتي من شأنها إزالة الفئة النَّشطة من الأزرار التي لم يتمّ نقرها. ستظهر تلك الفئة النَّشطة المُحدَّدة ضمن أنماط CSS لعرض لون خلفية رمادي إلى الزر الذي تمَّ نقره فقط. بعمل اختبارٍ سريعٍ في المُتصفِّح سيظهر عرض شرائح JavaScript يعمل على أكمل وجه. الإخراج إليك هذا المثال الحي ختامًا بهذا نكون قد انتهينا من إنشاء عرض شرائح JavaScript بإمكانه إضافة مظهرًا جميلًا إلى صفحات الوِّيب خاصَّتك. ترجمة -وبتصرُّف- للمقال: A Complete Tutorial On Creating Sliding-Enabled Slideshow Using jQuery.
  17. مِمَّا لا شكَّ فيه أنَّ هُناك قوالب ووردبريس رائعة المظهر ولكن هُناك العديد من الأمثلة على أشياءٍ بسيطة قد نُريد تغييرها في القالب. كلونٍ هُنا، حجم خطٍ هُناك ورُبَّما استدعاء للإجراء على الأزرار. تتمحور المُشكلة في أنَّ تعديل القالب حتَّى ولو كانَ تعديلًا بسيطًا يمنعُكَ من تحديثه إلى نُسخة جديدة في المُستقبل، هذا ببساطة راجع إلى أنَّه إذا قُمتَ بتحديثه فسيؤدِّي هذا إلى فُقدان كُلّ التغييرات التي أُحدِثَت عليه. تُقدِّم القوالب الفرعيَّة حلًّا لهذه المُشكلة عن طريق السَّماح لكَ باستخدام وظائف القالب المُختار إلى جانب إمكانيَّة التَّحديث دون الخوف من فُقدان تلكَ التَّعديلات. سنُقدِّم من خلال هذا الدرس توضيحًا للفائدة من استخدام قالب ووردبريس فرعي وكيفيَّة إنشائه. كيفيَّة عمل قوالب ووردبريس الفرعيَّة والفائدة من استخدامهاالقوالب الفرعيَّة هي قوالب مُنفصلة تعتمد على قالب أساسي في تأدية مُعظم وظائفها. إذا كُنتَ تستخدم قالب فرعي، فإنَّ ووردبريس سيقوم أوَّلًا بالتحقُّق من قالبك الفرعي ليتأكَّد من ما إذا كانت هُناك تأدية وظيفيَّة مُحدَّدة به. إذا لم يجد ووردبريس أيَّة تأدية وظيفية مُحدَّدة فسوف يستخدم القالب الأساسي مُباشرةً. تُعتبر هذه ميزة رائعة حيثُ أنَّها تُتيح لكَ التَّعديل على ما تُريد تعديله فقط. يجب استخدام القوالب الفرعيَّة إن كُنتَ تنوي تعديل ولو مُجرَّد حرف واحد في قالبك. هُناك سببين أساسيَّين للاستخدام، هما: التَّحديثات والتَّنظيم. 1. التَّحديثاتإذا قُمتَ بتعديل قالب بدون استخدام قالب فرعي فسيكون لديكَ خيارين بعد عمليَّة التَّعديل: قد تختار عدم تحديث قالبك في المُستقبل، أو تحديثه وخسارة كُلّ التغييرات المُضافة إلى القالب. رُبَّما يعملُ الخيار الثَّاني فنيًّا ولكنَّه أمرٌ غير مُقترح. حتَّى لو كان من السَّهل نسخ ولصق تعديلاتك، ما هي الفائدة من تضييع دقيقتين من وقتك على مُهمَّة قد تُعرِّضك للخطأ في كُلِّ تحديث؟ مُجرَّد التَّفكير في عدم تحديث القالب ليست فكرة جيِّدة. تُعتبر القوالب الغير مُحدَّثة من أكثر القوالب تعرُّضًا للاختراق. يجب عليكَ دائمًا الإبقاء -بدون استثناء- على كلٍّ من: ووردبريس، قالبك والإضافات مُحدَّثين بما يتناسب مع الوقت الحالي. 2. التَّنظيمعندما تُضيف شفرات لقالب موجود فإنَّك بهذا تُضيف إلى قاعدة شفرات قد تحتوي على الآلاف والآلاف من الأسطر. سيواجه المُطوِّرون ممن يعملون على موقعك (بالاضافة إليكَ بالتَّأكيد) أوقاتًا صعبة في تعقُّب التَّغييرات. نتيجة واحدة على الأقل لهذا الأمر هي تكاليف تطوير زائدة. حيثُ أنَّ القوالب الفرعيَّة تعود من جديد إلى القالب الأساسي -إلَّا إذا تمَّ تحديد ما هو غير ذلك- فإنَّ قالبك الفرعي هو عبارة عن مجموعة من التَّغييرات في قالبك الأساسي. يُمكن أن ينتج عن هذا تغييرات شاملة في حين أنَّ القالب الفرعي قد يحتوي على مُجرَّد مائة سطر من الشَّفرات. إنشاء قالب فرعييُعتبر إنشاء قالب فرعي أمرٌ بسيطٌ للغاية لدرجة أنَّه بامكانك تنفيذ هذا بمُجرَّد نسخ ولصق المثال الموجود بالأدنى. لإنشاء قالب فرعي لقالب عليكَ اتَّباع الخطوات التالية: أنشئ مُجلَّد قالب في تثبيت ووردبريس.أنشئ ملفّ نمط يحتوي على معلومات عن قالبك الفرعي.قُم بإيقاف تفعيل أنماط القالب الأساسي.يُمكنكَ تفعيل القالب الفرعي بمُجرَّد الانتهاء من تنفيذ هذه الخطوات وسيبدو موقعك تمامًا مثلما كان من قبل، الفرق الوحيد هو أنّ الموقع سيستخدم القالب الفرعي في عمله. دعونا الآن ندرس الخطوات أعلاه بالتَّفصيل. سأنشئ على سبيل المثال قالب فرعي للقالب الافتراضي Twenty Fourteen. أوَّلًا، توجَّه إلى مُجلَّد القالب وقُم بانشاء ملفًّا لقالبك الجديد. يُمكنكَ تسميته بالاسم الذي تُريد. من أجل التَّوضيح سنُسمِّي القالب twentyfourteen-child. الخطوة الثَّانية هي إنشاء ملفّ نمط. يجب تسمية هذا الملفّ style.css قُم بنسخ ولصق الشفرات التالية إلى الملف الذي أنشأته لتوِّك: /* Theme Name: Twenty Fourteen Child Theme URI: http://yourwebsite.com/twentyfourteen-child/ Description: My first child theme, based on Twenty Fourteen Author: Daniel Pataki Author URI: http://danielpataki.com Template: twentyfourteen Version: 1.0.0 Tags: black, green, white, light, dark, two-columns, three-columns, left-sidebar, right-sidebar, fixed-layout, responsive-layout, custom-background, custom-header, custom-menu, editor-style, featured-images, flexible-header, full-width-template, microformats, post-formats, rtl-language-support, sticky-post, theme-options, translation-ready, accessibility-ready, responsive-layout, infinite-scroll, post-slider, design, food, journal, magazine, news, photography, portfolio, clean, contemporary, dark, elegant, modern, professional, sophisticated Text Domain: twenty-fourteen-child */العُنصرين الأساسيَّين في هذه الشَّفرة هي السُّطور البادئة بـ "Theme Name" و"Template". يُخبر اسم القالب Theme Name ووردبريس عن اسم قالبك ويُعرَضُ هذا في مُنتقي القالب. أمَّا Template فيُحدِّد لووردبريس أيُّ القوالب يجب اعتباره القالب الأساسي. ما تبقى يصف نفسه بنفسه باستثناء نطاق النَّصّ text domain والوسوم tags. يُستخدم نطاق النَّصَّ لترجمة المقاطع. يجب أن يكون نطاق النَّصّ مُميّزٌ لقالبك ويجب استخدامه متى قُمتَ باستخدام دوال التَّرجمة. لمعلوماتٍ أكثر راجع I18n لمُطوِّري ووردبريس. قسم الوسوم هو قائمة من الوسوم التي تُستَخدم بواسطة مُستودع قالب ووردبريس. على سبيل المثال قد قُمتُ بالنَّظر في ملف style.css الخاصّ بالقالب الأساسي وببساطة قُمتُ بنسخ ولصق الوسوم من هُناك. إلى هذه النُّقطة فإنَّ قالبك الفرعي يعمل بشكلٍ جيِّد. إذا قُمتَ بتفعيله ثُمَّ إعادة تحديث الصَّفحة ستجد كُلّ مُحتواك بها ولكن لن تحتوي على أيّ تنسيق. ذكرتُ سابقًا أنَّ ووردبريس يبحثُ عن التأديَّات الوظيفيَّة في القالب الفرعي وإذا لم يجدها فإنَّه يعود مُجدَّدًا إلى القالب الأساسي. في حالتنا هذه فإن لدينا بالفعل ملف نمط ولذلك فإنَّ ووردبريس قد فهم أنَّه غير مسموح بتحميل ملفّ القالب الأساسي. وبُناءً عليه فإنَّنا سنحتاج إلى إدراج ملفّ نمط القالب الأساسي لكي نتأكَّد من أنَّنا قد قُمنا بتحميله. يُمكن عمل هذا في ملفّ القالب function.php دعونا نُنشيء الآن هذا الملفّ وننسخ الشفرات التالية به: add_action( 'wp_enqueue_scripts', 'enqueue_parent_styles' ); function enqueue_parent_styles() { wp_enqueue_style( 'parent-style', get_template_directory_uri().'/style.css' ); }إذا لم تكُن لديك أيَّة فكرة عن PHP وكُلّ ما تُريده هو تغيير بعض الأنماط فقط فلا تهتمّ كثيرًا لمعرفة سبب عمل هذا. يُمكنكَ الآن التوجُّه ببساطة إلى ملف النَّمط والبدء بعمل التَّغييرات التي تُريد. إذا كان لديكَ فضول لمعرفة المزيد عن الإدراج يُمكنكَ الاطِّلاع على صفّ وتسجيل ملفات Javascript و CSS في قوالب ووردبريس. تقنية القوالب الفرعيَّةإذًا كيف يعمل القالب الفرعي؟ تعملُ القوالب الفرعية في مستوى الملف. عند استخدام ملف خلال عملية تحميل قالب فيتمّ التحقُّق من ما إذا كان هذا الملفّ موجود في القالب الفرعي. إذا كان الملف موجودًا، يتمّ استخدام محتوى هذا الملف. أمَّا إذا لم يكن موجودًا، فيتمّ استخدام نفس الملف في القالب الأساسي. هُناكَ استثناءٌ واحد لهذه القاعدة ألا وهو ملفّ دوال القالب. يتمّ تحميل ملف functions.php الموجود في كلٍّ من القالب الأساسي والقالب الفرعي. إذا قامت دوال القالب الفرعي باستبدال دوال القالب الأساسي فقد تواجه موقعًا به خلل أو قد تحتاج إلى نسخ ولصق محتويات ملف دوال القالب الأساسي كلُّها إلى ملف القالب الفرعي والتي تُفشِلُ نوعًا ما الهدف من تمديد قالب. خطوات سير العمل عند تعديل التأدية الوظيفيَّة هي كالتَّالي: إذا أردتَ عمل تعديلات على التَّرويسة header فعليكَ نسخ ولصق ملفّ القالب الأساسي header.php إلى قالبك الفرعي. قُم بتعديل الملفّ كما يحلو لك، قُم بحفظ الملف بعد الانتهاء من التَّعديل وشاهد نتائج عملك. بعض المُلاحظات إلى صانعي قوالب ووردبريسإذا كُنتَ تُنشيء قالبكَ الخاصّ فهُناكَ بعض الإرشادات التي رُبَّما عليكَ اتِّباعها من أجل بناءٍ أسهل للقالب الفرعي. الإرشادين الأهمّ هما: معرفة الفرق بين دالَّتي ()get_stylesheet_directory و()get_template_directory، وإنشاء دوال قابلة للإضافة. 1. المُجلَّد الصحيحعليك -عند الرَّبط مع مُمتلكات باستخدام الدَّوال المذكورة- أن تكون على دراية بأنَّ عائلة دوال get_template_ ستُشيرُ دائمًا إلى مُجلَّد القالب الأساسي في حين أنَّ عائلة دوال get_stylesheet_ ستُشيرُ دائمًا إلى مُجلَّد القالب الفرعي. <a href="http://twitter.com/danielpataki"><img src="<?php echo get_template_directory_uri() ?>/images/twitter.png" alt='Twitter Logo'>Follow Me</a> <a href="http://github.com/danielpataki"><img src="<?php echo get_stylesheet_directory_uri() ?>/images/github.png" alt='Github Logo'>On Github</a>في المثال أعلاه، يأخذ الرابط الأول صورته من القالب الأساسي في حين أنَّ الرابط الثاني يأخذ صورته من القالب الفرعي. ليس هُناك أفضيلة لطريقة على الأخرى، اختيار احداهما هو أمرٌ يرجع إليك. ميزة استخدام ()get_stylesheet_directory_uri هي أنَّه يُمكن لمُطوِّري القالب الفرعي استخدام صورهم الخاصَّة ويتمّ هذا ببساطة عن طريق إنشائها في الموقع المُناسب. على الجانب الآخر، إذا لم تكن الصور موجودة في القالب الفرعي فلن يتم عرضها على الإطلاق. سبب هذا هو أنَّه إذا كان القالب الفرعي مُفَعَّل فإنَّ دالَّة ()get_stylesheet_directory_uri لا تتحقَّق من (ولا تعرف) ما هو الملفّ الذي تقوم أنتَ بتحميله ولذلك فلن تقوم الدَّالَّة بالتحقُّق من وجوده أصلًا. ستقوم الدَّالَّة دائمًا بإعادة مُعرِّف الموارد المُوحَّد URI للقالب الفرعي. 2. دوال قابلة للتَّعديلالطريقة الأخرى التي عليكَ استخدامها هي ما يُسمِّيها ووردبريس دوال قابلة للإضافة. يسمح هذا لمالكي القالب الفرعي الكتابة على الدوال التي قُمتَ بتعريفها في القالب الأساسي. يشتمل هذا على إحاطة دوالّك بتأكيدات ()function_exists. لنفترض أنَّكَ قد قُمتَ بإنشاء دالَّة تُسمَّى ()my_meta لعرض بادئة تدوينة مُخصَّص. لا يوجد مجال للقالب الفرعي لتعديل هذه الدَّالَّة حيثُ أنَّه لا يُمكن تعريفها مرَّتين. حلّ المُشكلة هو إنشاء هذه الدَّالَّة إذا لم يتمّ تعريفها (تذكَّر، يتمّ تحميل ملف دالَّة القالب الفرعي أوَّلًا). if ( !is_defined( 'my_meta' ) ) { function my_meta() { // code for postmeta here } }ختامًايُمكنكَ باستخدام بعض خطوات النَّسخ واللَّصق البسيطة إنشاء بيئة مُستقبليَّة لقالبك والتي ستُبعد عنكَ الكثير من المتاعب. رغم أنَّه من المُغري استخدام مُحرِّر القالب المُدمج في ووردبريس، إلَّا أنَّه غالبًا ما يُسبِّب أخطاءً أكثر مِمَّا يحلّ في حالة عدم استخدام قالب فرعي. قُم باستغلال بعض الوقت لاتِّباع الخطوات الموجودة بهذا الدَّرس وسيكون موقعك ومُطوِّره شاكرين لفعلكَ هذا. أخيرًا، إن كان لديكَ بعض النَّصائح حول القوالب الفرعيَّة، لا تتردَّد في اعلامنا بها.
  18. لماذا إعادة تقديم؟ لسوء سُمعة JavaScript حيثُ أنَّها أكثر لُغة برمجة يُساء فهمها في العالم. على الرَّغم من أنَّه في كثيرٍ من الأحيان يتمّ وصفها لُعبة على سبيل السخريّة، إلَّا أنّهُ أسفل بساطتها الخادعة تقعُ بعض ميزات لغةٍ قويّة، أحدُها أنَّها الآن تُستَخدم من قِبَل عددٍ لا يُصدّق من التطبيقاتِ عاليةِ المستوى، ويُبيِّن ذلك أنَّ معرفةً أعمق بهذه التكنولوجيا إنّما هي مهارة مُهمّة لأي مُطوّر لشبكة الإنترنت أو المحمول. من المُفيد أن نبدأ بفكرةٍ عامَّة عن تاريخ هذه اللُّغة. تم إنشاء JavaScript في عام 1995 من قبل Brendan Eich، وهو مهندس في Netscape، وصدرت أولًا مع Netscape 2 في عام 1996. في الأصل كان مُتّفقٌ تسميتها LiveScript، ولكن تمَّ تغيير اسمها في قرارٍ تسويقيٍّ مشؤوم كمُحاولة للاستفادة من شعبية لُغة Java - التابعة لـ Sun Microsystems- على الرغم من أنَّ هُناك عدد قليل جدًا من القواسم المُشتركة بين اللغتين. لقد كان هذا مصدرًا للارتباك منذ ذلك الحين. بعد ثلاثةِ أشهرٍ أطلقت Microsoft نُسخة مُعظمُها مُتوافق مع اللُّغة أسمتها JScript مع IE . قدّمت Netscape اللُّغة إلى Ecma International، وهي مُنظّمةُ معاييرٍ أوروبيّة، وأسفرَ ذلك عن الطبعةِ الأولى من ECMAScript القياسيّة في عام 1997. تلقّت اللُغة عملية تحديث كبيرة كما في ECMAScript Edition 3 في عام 1999، وبَقيتْ مُستقرّة إلى حدٍ كبير منذ ذلك الحين. تمّ التخلي عن الطبعة الرابعة بسبب الخلافات السياسيّة بشأن تعقيد اللُّغة. شكَّلَتْ أجزاءٌ كثيرة من الطبعة الرابعة أساسَ الطبعة ECMAScript 5، التي نُشِرَت في ديسمبر من عام 2009 والطبعة الكبرى 6 والتي سيتمّ نشرها في عام 2015. من أجل الاعتياد، سوف أستخدمُ مُصطلحَ JavaScript طوال الوقت. خلافًا لمُعظم لغاتِ البرمجة، ليس لدى لغة JavaScript مفهوم الإدخال أو الإخراج. إنّما هي مُصمَّمةٌ لتعمل كلغةِ برمجةٍ نصيّة في بيئة استضافة، والأمرُ متروكٌ للبيئة المضيفة لتوفير آليات للتواصل مع العالم الخارجي. بيئةُ الاستضافةِ الأكثرِ شيوعًا هي المُتصفِّح، ولكن بالإمكان أيضًا العثور على مُفسّر JavaScript في Adobe Acrobat, Photoshop, SVG images, Yahoo!'s Widget engine، فضلًا عن البيئاتِ المُتاحةِ من جانب الخادوم مثل node.js. إلا أن قائمة المناطق حيث يتم استخدام JavaScript فقط تبدأ هُنا. تشتملُ اللُّغة أيضًا على قواعد بيانات NoSQL، مثل Apache CouchDB مفتوح المصدر، أجهزة الحاسوب المضمّنة أو بيئات سطح المكتب كاملة، مثل GNOME (واحدة من واجهات المستخدم الرسوميّة الأكثر شعبيّة لأنظمة التشغيل جنو / لينكس). نظرة عامةJavaScript هي لغة ديناميكيّة كائنيّة المنحنى. لديها أنواع types ومُشغِّلين operators، كائنات objects قياسيّة مُدمجة ووظائف methods. يأتي بناءُ الجُملةِ في JavaScript من لُغَتَي Java و C، وتنطبقُ العديدُ من الهياكل في تلك اللغات في JavaScript كذلك. إلَّا أنَّ أحد الفروق الرئيسيَّة هو أنَّه لا توجد فئات Classes في JavaScript. بدلًا من ذلك، يتم إنجاز وظائف الفئة عن طريق نماذج الكائن object prototypes. الفرقُ الرئيسي الآخر هو أن الدوال functions هي كائنات، تُعطى الدوال القدرة على الاحتفاظ بتعليماتٍ برمجيَّة قابلة للتنفيذ وتمريرها مثلها مثل أي كائن آخر. دعونا نبدأ من خلال النَّظر داخل لبنة بناء أي لغة: الأنواع. تقوم برامج JavaScript بمُعالجة القيم، وتنتمي كل تلك القيم إلى نوع. أنواع JavaScript هي: عدد Numberسلسلة Stringمنطقيَّة Booleanدالّة Functionكائن Objectرمز Symbol (جديد في الإصدار 6)كذلك undefined وnull، ويُعتبر هذين النوعين غريبين بعض الشيء. وهُناكَ أيضًا المصفوفة Array، والتي هي نوع خاص من الكائن. والتاريخ Date والمُنشئ RegExp، وهي كائناتٌ تحصلُ عليها مجانًا. ولكي نكون دقيقين من الناحية الفنيّة، الدوال ما هي إلَّا نوعٌ خاصٌّ من الكائن. ولذلك فإن الرسم البياني للنوع يبدو أكثر مثل ما يلي: عدد Numberسلسلة Stringمنطقيَّة Booleanرمز Symbol (جديد في الإصدار 6)كائن Objectدالّة Functionمصفوفة Arrayتاريخ Dateمُنشئ RegExpلا شيء Nullغير مُحدَّد Undefinedكذلك هُناك بعض أنواع الخطأ Error المُدمجة. لكن على كلِّ حال الأمور أسهل كثيرًا إذا اعتمدنا على الرسم البياني الأوَّل. الأرقامالأرقام في JavaScript هي "قِيَم IEEE 754 الدقيقة المُزدوجة في شكل 64-بِت"، وفقًا للمواصفات. لهذا المعنى بعض العواقب المُثيرة للاهتمام. ليس هُناكَ شيءٌ في JavaScript يُشبه العدد الصحيح integer، لذلك عليك أن تكون حذرًا قليلًا مع عمليّاتك الحسابيّة إذا كنتَ معتادًا على الرياضيات في C أو Java. احترس من أشياء مثل: 0.1 + 0.2 == 0.30000000000000004في المُمَارسة العمليّة، يتمّ التعامل مع القيم كما أعداد صحيحة من 32 بِت bit (ويتم تخزينهم بتلك الطريقة في بعض تطبيقات المُتصفِّح)، والتي يمكن أن تكون هامّة للعمليّات التي تستخدم نوع بِت. العوامل الحسابيّة القياسيّة مدعومة، بما في ذلك الجمع والطرح ومُعامل الحساب modulus أو (remainder)، وهكذا دواليك. هناك أيضًا كائن مُدمَج نسيتُ ذِكرَهُ سلفًا يُسمّى Math والذي يُمكنكَ استخدامَهُ إذا كنت ترغب في أداءِ دوالٍّ وثوابت رياضيّة أكثر تقدمًا: Math.sin(3.5); var d = Math.PI * r * r;يُمكنكَ تحويل سلسلة إلى عدد صحيح باستخدام الدالّة المُدمجة ()parseInt. هذه الدالّة تأخذ قاعدة للتحويل كمُعامِل argument ثاني اختياري، والتي ينبغي عليكَ توفيرها دائمًا: parseInt("123", 10); // 123 parseInt("010", 10); // 10رُبَّما تحصُل على نتائج مُذهلة في المُتصفِّحات القديمة (قبل عام 2013) إذا لم توفِّر قاعدة التحويل: parseInt("010"); // 8حَدَثَ ذلك لأن دالّة ()parseInt قرّرت مُعامَلة السلسلة كثُمانيّة octal نظرًا لأن 0 هي الرَّائدة. إذا كُنتَ ترغب في تحويل رقم ثنائيّ binary إلى عدد صحيح integer، فقط يتمّ تغيير القاعدة: parseInt("11", 2); // 3وبالمثل، يمكن تحليل أرقام الفاصِلة العائمة floating point numbers باستخدام الدالّة المُدمجة ()parseFloat والتي تَستَخدِم base 10 دائمًا خلافًا لرفيقتها ()parseInt. يُمكنكَ أيضًا استخدام عامل التشغيل الأحاديّ + لتحويل القيم إلى أرقام: + "42"; // 42يتمّ إرجاع قيمة خاصّة تُسمّى NaN (اختصار لـ”Not a Number”) إذا كانت السلسلة غير رقميّة: parseInt("hello", 10); // NaNNaN سامّة: إذا قُمتَ بتقديمها كمدخل input إلى أي عمليَّة حسابيَّة فإن النتيجة ستكون أيضًا NaN: NaN + 5; // NaNيُمكنكَ اختبار NaN باستخدام الدالّة المُدمجة ()isNaN: isNaN(NaN); // trueلدى JavaScript القيم الخاصّة Infinity و-Infinity: 1 / 0; // Infinity -1 / 0; // -Infinityيُمكنكَ اختبار قيم Infinity و–Infinity وNaN باستخدام الدالّة المُدمجة ()isFinite: isFinite(1/0); // false isFinite(-Infinity); // false isFinite(NaN); // falseمُلاحظة: تقوم دالَّتَي ()parseInt و()parseFloat بتحليل سلسلة حتى تصلا إلى حرفٍ غير صالح لشكل الرَّقم المُحدَّد، بعد ذلك يتمّ إرجاع الرقم الذي تم تحليله إلى تلك النقطة. رغم ذلك فإن المُعامِل "+" يقوم ببساطة بتحويل السلسلة إلى NaN إذا كان هُناك أيّ حرفٍ غير صالح في السلسلة. جرّب محاولة تحليل السلسلة "10.2abc" باستخدام كل طريقة مع نفسك في وحدة التَّحكُّم console، وسوف تفهم الاختلافات بشكلٍ أفضل. السلاسلالسلاسل في JavaScript هي مُتتابعات من الأحرف. ولتعريفٍ أكثر دقة، هي مُتتابعات من أحرف Unicode، يتمّ تمثيل كُل حرف في عدد 16 بِت. لا بُدَّ أنَّ هذا نبأ سار لأي شخص قد تعامل مع نظام التدويل. إذا كُنتَ ترغب في تمثيل حرف واحد، عليكَ استخدام سلسلة من طول 1 فقط. للعثور على طول سلسلة، قٌم باستدعاء خاصيّتها length: "hello".length; // 5هذه أول فُرشاة لدينا مع كائنات JavaScript! هل ذكرتُ لكَ أنَّ بامكانكَ استخدام السلاسل مثل الكائنات أيضًا؟ لديهم وظائف تسمحُ لكَ بمُعالجة السلسلة والوصول إلى معلومات عنها: "hello".charAt(0); // "h" "hello, world".replace("hello", "goodbye"); // "goodbye, world" "hello".toUpperCase(); // "HELLO"أنواع أخرىتُميّز JavaScript ما بين null، وهي القيمة التي تدل على لا شيء (ويمكن الوصول إليها من خلال طريقة واحدة ألا وهي استخدام الكلمة المحجوزة null)، وundefined، وهي قيمة من نوع 'غير معروف' التي تُشير إلى قيمة غير مُهيَّأة - أي قيمة لم يتمّ تعيينها بعد. سوف نتحدَّث عن المُتغيّرات في وقتٍ لاحق، ولكن يُمكن تعريف مُتغيّر في JavaScript دون تحديد قيمة له. إذا قمتَ بذلك، فإنَّ نوع المُتغيّر يُصبِح undefined. في الواقع نوع undefined ثابت. لدى JavaScript نوع Boolean مع القيم الممكنة true وfalse (وكلاهما كلمات محجوزة). يمكن تحويل أيّ قيمة إلى قيمة منطقيّة وفقًا للقواعد التالية: 1- تُصبِح كل من (false، 0، سلسلة فارغة (" ")، NaN، null وundefined) false. 2- تُصبِح كل القيم الأخرى true. يُمكنكَ إجراء هذا التحويل صراحة باستخدام دالَّة ()Boolean: Boolean(""); // false Boolean(234); // trueولكن نادرًا ما يكون هذا ضروريًّا، حيث أن JavaScript ستؤدّي بصمتٍ هذا التحويل عندما تتوقَّع قيمة منطقيَّة، مثل في عبارة if (انظر أدناه). لهذا السبب، ببساطة نذكُر أحيانًا "القيم الحقيقيّة" و"القيم الزائفة" قاصدين القيم التي تُصبح true وfalse على التوالي عند تحويلها إلى القيم المنطقيّة. بدلًا من ذلك يُمكن تسمية هذه القيم "truthy" و"falsy" على التوالي. العمليّات المنطقيّة مثل &&، logical and) || (logical or و! (logical not) مُعتمَدة. انظر أدناه. المُتغيّراتيتمّ تعريف المُتغيّرات الجديدة في JavaScript باستخدام var: var a; var name = "simon";إذا قمتً بتعريف مُتغيّر دون تعيين أيّ قيمة له، فإن نوعه يُصبِح undefined. هناك فارق هام عن لغات أخرى مثل Java ألا وهو أنّ الكُتَل blocks في JavaScript لا تملك نطاق scope؛ فقط الدوال هي التي لها نطاق. لذلك إذا تم تعريف مُتغيّر باستخدام var في جملة مُجمّعة (على سبيل المثال داخل if control structure)، سيكون المُتغيِّر مرئي من قِبَل الدالّة كاملة. إلَّا أنَّه بدءًا من ECMAScript الطبعة 6، تَسمحُ لك تعريفات let وconst امكانيَّة إنشاء مُتغيّرات block-scoped. المُعامِلاتمُعامِلات JavaScript الرقميّة هي +، -، *، / و٪ - وهو عامل ما تبقى. يتمّ تعيين القيم باستخدام = وهناك أيضًا جُمل تعيين مُركبّة مهمّة مثل += و-=. هذه تمتد إلى x = x مُعامِل y. x += 5 x = x + 5يُمكنكَ استخدام ++ و-- للزيادة والإنقاص على التوالي. كذلك بإمكانك أن تَستَخدِم هذه المُعامِلات كمُعامِلات prefix أو postfix. يقومُ المُعامِل + بربط السلسلة: "hello" + " world"; // "hello world"إذا قمتَ بإضافة سلسلة لعدد (أو قيمة أخرى) يتمّ تحويل كل شيء إلى سلسلة أولًا. يُمكن لما يلي أن يوضِّح المقصود: "3" + 4 + 5; // "345" 3 + 4 + "5"; // "75"إضافة سلسلة فارغة إلى شيء هي وسيلة مفيدة لتحويله إلى سلسلة. يُمكن إجراء المُقارنات في JavaScript باستخدام <، >، <= و =>. تَعمَلُ هذه المُقارنات مع السلاسل والأرقام على حدٍّ سواء. تبدو المُساواة أوضح قليلًا عن نظيراتها. تقوم المُساواة المزدوجة == بإجبار تغيير النَّوع إذا قُمتَ باعطائها أنواع مختلفة، وتُعطي نتائج مُثيرة للاهتمام في بعض الأحيان: "dog" == "dog"; // true 1 == true; // trueلتجنُّب إجبار النَّوع، استخدم المساواة الثلاثيَّة: 1 === true; // false true === true; // trueهُناكَ أيضًا != و!==. لدى JavaScript أيضًا مُعامِلات أُحاديّة. إذا كنت ترغب في استخدامها. هياكل التَّحكُّملدى JavaScript مجموعة مُماثِلة لهياكل التَّحكُّم الموجودة في لغات أخرى مثل عائلة C. العبارات الشرطيَّة مدعومة بواسطة if وelse؛ يُمكنكَ سَلسَلَتهم معًا إذا أردت: var name = "kittens"; if (name == "puppies") { name += "!"; } else if (name == "kittens") { name += "!!"; } else { name = "!" + name; } name == "kittens!!"لدى JavaScript حلقات while وحلقات do-while. الأولى جيِّدة لعمليات الحلقات البسيطة؛ والثانية مع تلك الحلقات إذا كنت ترغب في التأكُّد من أن جسد الحلقة يتمّ تنفيذه مرة واحدة على الأقل: while (true) { // an infinite loop! } var input; do { input = get_input(); } while (inputIsNotValid(input))For loop في JavaScript هي نفسها التي في C وJava: فهي تُتيح لكَ توفير معلومات التَّحكُّم للحلقة الخاصّة بك في سطرِ واحد. for (var i = 0; i < 5; i++) { // Will execute 5 times }يَستخدم المُعامِلين && و|| دائرة منطقيَّة قصيرة، وهو ما يعني أنَّها تعتمد على مُعامِلها الأوّل في إذا ما كانت ستُنفِّذ مُعامِلها الثاني. وهذا مُفيد لفحص الكائنات الفارغة قبل محاولة الوصول إلى سماتها: var name = o && o.getName();أو لوضع قيم افتراضيّة: var name = otherName || "default";لدى JavaScript مُعامِل ثُلاثي للتعبيرات الشرطيَّة: var allowed = (age > 18) ? "yes" : "no";يُمكن استخدام جُملة switch مع الفروع المتعدِّدة استنادًا إلى عددٍ أو سلسلة: switch(action) { case 'draw': drawIt(); break; case 'eat': eatIt(); break; default: doNothing(); }إذا لم تقم بإضافة break سوف يتوقّف التنفيذ عن المستوى التالي. وهذا نادرًا جدًا ما تُريد أن يحدث - في واقع الأمر هي تستحقّ وصفها على وجه التحديد fallthrough في تعليق إذا كُنتَ حقَا من المفترض أن تساعد في التصحيح: switch(a) { case 1: // fallthrough case 2: eatIt(); break; default: doNothing(); }يُعتبر شرط default اختياري. يُمكنكَ الحااق تعبيرات في كل من جزء switch وcase إذا أردت ذلك. تُجرَي المُقارنات بين اثنين باستخدام ===: switch(1 + 3) { case 2 + 2: yay(); break; default: neverhappens(); }الكائناتيُمكن اعتبار كائنات JavaScript كمجموعات بسيطة من أزواج name-value. على هذا النحو يمكن تشبيهها بـ: * القواميس Dictionaries في لغة Python * التجزئات Hashes في لغتي Perl وRuby * جداول التجزئة Hash Tables في لغتي C و C++ * HashMaps في لغة Java * مصفوفات الترابط Associative arrays في لغة PHP حقيقة أنّ هياكل البيانات تُستخدم في نطاق واسع ما هو إلَّا دليلٌ على تنوُّعها. وحيثُ أنَّ كل شيء (أنواع الشريط الأساسيَّة bar core types) في JavaScript هو كائن، فإنَّ أيّ برنامج JavaScript يحتوي بطبيعة الحال على قدرٍ كبيرٍ من عمليَّات البحث في جدول التجزئة. وهذا شيءٌ جيِّد والعمليَّات سريعة جدًا! جزء الـ"اسم" هو سلسلة JavaScript، في حين أنَّ القيمة يُمكن أن تكون أي قيمة لـ JavaScript - بما في ذلك المزيد من الكائنات. يَسمحُ هذا لك بامكانيَّة بناء هياكل بيانات من نوع التعقيد التعسُّفي. هُناكَ طريقتان أساسيَّتان لإنشاء كائن فارغ: var obj = new Object();و: var obj = {};و: function Person(name, age) { this.name = name; this.age = age; } // Define an object var You = new Person("You", 24); // We are creating a new person named "You" // (that was the first parameter, and the age..)هذه الطُرق مُتعادِلة لغويًّا؛ يُطلق على الثانية جُملة الكائن الحرفيّة، وهي الأكثر ملاءمة. بناء الجملة هذه هو أيضًا جوهر شكل JSON لذلك ينبغي تفضيل استخدامها في جميع الأوقات. يُمكن الوصول إلى سِمَات الكائن بمُجرّد إنشائه بطريقة من اثنتين: obj.name = "Simon"; var name = obj.name;و: obj["name"] = "Simon"; var name = obj["name"];هاتين الطريقتين مُتعادِلتين لُغويًا أيضًا. للطريقة الثانية ميزة ألا وهي أنَّ اسم الصفة المُميّزة property يتم توفيره كسلسلة، مما يعني أنَّه يُمكن حسابها في وقت التشغيل. رغم ذلك استخدام هذا الأسلوب يمنع بعض تحسينات مُحرِّك ومُصغِّر حجم JavaScript من التطبيق. أيضًا لتحديد set والحصول على get يُمكِنُكَ استخدام الخصائص ذات الأسماء المُتعارَف على أنَّها كلمات محجوزة: obj.for = "Simon"; // Syntax error, because 'for' is a reserved word obj["for"] = "Simon"; // works fineمُلاحظة: ابتداءً من EcmaScript 5، يُمكن استخدام الكلمات المحجوزة كأسماء خاصيّة الكائن المُميّزة object property مُجرّدة، وهذا يُعني أنَّها لا تحتاج إلى أن يتمّ وضعها بين اقتباسات عند تحديد حرفيَّات الكائن. راجع ES5 في Spec. يُمكن استخدام جُملة الكائن الحرفيّة لتهيئة كائن في مُجمَله: var obj = { name: "Carrot", "for": "Max", details: { color: "orange", size: 12 } }يُمكن سَلسَلة الوصول إلى الخاصيّة المُميّزة معًا: obj.details.color; // orange obj["details"]["size"]; // 12المصفوفاتفي الواقع المصفوفات في JavaScript هي نوعٌ خاصٌّ من الكائن. تعملُ المصفوفات كثيرًا مثل الأشياء العاديّة (يُمكن الوصول إلى الخصائص العدديّة باستخدام صياغة [] فقط) ولكن لدى المصفوفات خاصيَّة سحريَّة تُسمَّى ‘length’. هذه الخاصيَّة دائمًا ما تَزِيد بواحد عن أعلى مؤشِّر في المصفوفة. هُناك طريقة واحدة لخلق المصفوفات وهي على النحو التالي: var a = new Array(); a[0] = "dog"; a[1] = "cat"; a[2] = "hen"; a.length; // 3هُناك تأشير أكثر ملاءمة ألا وهو استخدام المصفوفات الحرفيَّة: var a = ["dog", "cat", "hen"]; a.length; // 3لاحظ أن array.length ليس بالضرورة عدد العناصر في المصفوفة. مع مراعاة ما يلي: var a = ["dog", "cat", "hen"]; a[100] = "fox"; a.length; // 101تذكَّر - طول المصفوفة يزيد بواحد عن أعلى مؤشِّر بها. إذا استعلمتَ عن مؤشِّر مصفوفة غير موجود، تحصل على نوع غير مُعرَّف undefined: typeof a[90]; // undefinedإذا أخذتَ ما سبق في الاعتبار، يمكنك التكرار عبر مصفوفة باستخدام ما يلي: for (var i = 0; i < a.length; i++) { // Do something with a[i] }هذه الطريقة غير فعّالة بعض الشيء حيثُ أنّكَ تقوم بالبحث عن الخاصيَّة length مرّة واحدة كل حلقة. تحسينٌ لهذا ما يلي: for (var i = 0, len = a.length; i < len; i++) { // Do something with a[i] }هذا أجمل في المظهر ولكن ذو لغة محدودة: for (var i = 0, item; item = a[i++];) { // Do something with item }نقوم هُنا بإعداد مُتغيّرين. يتم اختبار التعيين أيضًا في الجزء الأوسط من الحلقة للتأكُّد من المصداقيّة - إذا نَجَحَت، ستستمرّ الحلقة في العمل. وحيثُ أن i يتزايد في كل مرّة، سيتمّ تعيين العناصر من المصفوفة إلى عناصر في ترتيب تسلسلي. تتوقّف الحلقة عندما يتمّ العثور على قيم "falsy" (مثل نوع undefined). يجبُ عليكَ استخدام هذه الحيلة فقط مع المصفوفات التي تَعْلَمُ أنَّها لا تحتوي على قِيَم "falsy" (على سبيل المثال مصفوفات من كائنات أو نموذج كائن المُستند DOM). إذا كُنتَ تقوم بالتكرار خلال بيانات رقميَّة يُمكن أن تشمل 0 أو بيانات سلسلة يُمكن أن تشمل سلسلة فارغة يجبُ عليكَ بدلًا من ذلك استخدام تعبير i, len. هُناك طريقة أخرى للتكرار وهي استخدام حلقة for…in. لاحظ أنَّهُ إذا قامَ شخصٌ بإضافة خصائص جديدة لـ Array.prototype فإنَّه سيتم تكرارهم من قِبَل هذه الحلقة أيضًا: for (var i in a) { // Do something with a[i] }إذا كُنتَ ترغب في إلحاق عنصر إلى مصفوفة، ببساطة قُم بذلك كما يلي: a.push(item);تأتي المصفوفات مع عدد من الوظائف. انظر أيضًا وثائق كاملة عن أساليب المصفوفة. الوصفاسم الدالَّةتقوم بإرجاع سلسلة مع toString() من كل عنصر مفصولة بفواصل.a.toString()تقوم بإرجاع سلسلة مع toLocaleString() من كل عنصر مفصولة بفواصل.a.toLocaleString()تقوم بإرجاع مصفوفة جديدة مع عناصر مضافة إليها.a.concat(item1[, item2[, ...[, itemN]]])تقوم بتحويل المصفوفة إلى سلسلة - قيم محدَّدة من قبل العامل المُتغيِّر sepa.join(sep)تقوم بإزلة وإرجاع العنصر الأخير.a.pop()تقوم push بإضافة عنصر واحد أو أكثر في النهاية.a.push(item1, ..., itemN)تقوم بعكس المصفوفة.a.reverse()تقوم بإزالة وإعادة العنصر الأول.a.shift()تقوم بإرجاع مصفوفة فرعيَّة (Sub-array).a.slice(start, end)تقوم بأخذ دالَّة مقارنة اختياريَّة.a.sort([cmpfn])تتيح لك تعديل مصفوفة عن طريق حذف قسم واستبداله بمزيد من العناصر.a.splice(start, delcount[, item1[, ...[, itemN]]])تقوم بإلحاق عناصر إلى بداية المصفوفة.a.unshift([item]) الدوالّالدوالّ هي العنصر الأساسيّ في فهم JavaScript جنبًا إلى جنبٍ مع الكائنات. لا يُمكن للدالّة المُجرّدة أن تكون أسهل من التالية: function add(x, y) { var total = x + y; return total; }تدلُّ التعليمات البرمجيَّة هذه على كل شيء يُمكن معرفته عن الدوال الأساسية. يُمكن لدالّة JavaScript أن تستقبل 0 أو أكثر مما تُدعى مُتغيّرات. يُمكن لجسم الدالّة أن يحتوي على عدد ما تُريد من الجُمل statements، ويُمكن أن تُعرّف مُتغيّراتُها الخاصّة والتي تكون محليّة بالنسبة لتلك الدالّة. يُمكن استخدام جُملة return لإرجاع قيمة في أي وقت ثُمَّ إنهاء الدالّة. إذا لم يتمّ استخدام أيّ جُملة إرجاع (أو تمّ استخدامها وكانت فارغة بدون قيمة) فإن JavaScript تقوم بإرجاع نوع 'غير مُعرَّف'. تُعتبر المُتغيّرات المُسمّاه كمبادئ توجيهيّة أكثر من أي شيء آخر. يُمكنكَ استدعاء دالّة دون تمرير المُتغيّر الذي تتوقّعه الدالّة، في هذه الحالة سيتمّ تعيين المُتغيّر كنوع غير مُعرَّف. add(); // NaN // You can't perform addition on undefinedيُمكنكَ أيضًا تمرير عدد من المُتغيّرات أكثر من العدد الذي تتوقّعه الدالّة: add(2, 3, 4); // 5 // added the first two; 4 was ignoredقد يبدو هذا سخيفًا بعض الشيء ولكن لدى الدوال خاصيَّة الوصول إلى مُتغيّرات إضافيّة داخل أجسامهم تُسمّى arguments، والتي هي كائن مثل المصفوفة تحتوي على كافّة القيم التي تمَّ تمريرُها إلى الدالّة. دعونا نُعيد كتابة دالّة الجمع لتأخذ عدد ما نُريد من القيم: function add() { var sum = 0; for (var i = 0, j = arguments.length; i < j; i++) { sum += arguments[i]; } return sum; } add(2, 3, 4, 5); // 14رغم ذلك فإنَّ هذا في الحقيقة ليس له أيّ فائدة على مُجرَّد كتابة 2 + 3 + 4 + 5. دعونا نقوم بإنشاء دالّة المتوسِّط: function avg() { var sum = 0; for (var i = 0, j = arguments.length; i < j; i++) { sum += arguments[i]; } return sum / arguments.length; } avg(2, 3, 4, 5); // 3.5هذا مفيدٌ جدًا ولكنَّه يُظهِر مُشكلة جديدة. تأخذ دالّة ()avg قائمة من المُتغيّرات مفصولٌ بينَ كلٍّ منها بفاصِلة - ولكن ماذا لو كُنتَ تُريد أن تجد مُتوسّط مصفوفة؟ يُمكنك كتابة الدالّة على النحو التالي: function avgArray(arr) { var sum = 0; for (var i = 0, j = arr.length; i < j; i++) { sum += arr[i]; } return sum / arr.length; } avgArray([2, 3, 4, 5]); // 3.5سيكونُ من الجميل أن يُصبح بمقدورِنا إعادة استخدام الدالَّة التي قُمنا بإنشائِها مُسبقًا. لحُسن الحظّ، تُمكنُّكَ Javascript من استدعاء دالّة مع مصفوفة من قيم المُتغيّرات العشوائيّة، وذلكَ باستخدام وظيفة apply() من أي كائن دالّة. avg.apply(null, [2, 3, 4, 5]); // 3.5قيمة المُتغيّر الثانية لـ ()apply هي المصفوفة المُستخدمة كقيم المُتغيّرات؛ سيتم نقاش المُتغيّر الأول في وقت لاحق. هذا يؤكد حقيقة أن الدوالّ هي كائنات أيضًا. تُتيح لكَ Javascript إنشاء وظائف مجهولة. var avg = function() { var sum = 0; for (var i = 0, j = arguments.length; i < j; i++) { sum += arguments[i]; } return sum / arguments.length; }هذا هو ما يُعادل لُغويًا نموذج دالّة ()avg. إنَّها قويَّة للغاية حيثُ أنها تُتيحُ لكَ وضع تعريف دالَّة كاملة في أي مكان يُمكنكَ عادة وضع تعبير expression به. يُتيحُ هذا كل أنواع الحِيَل. إليكَ طريقة لـ "اخفاء" بعض المُتغيّرات المحليّة – مثل نطاق الكتلة block scope في لغة C: var a = 1; var b = 2; (function() { var b = 3; a += b; })(); a; // 4 b; // 2تسمحُ لكَ JavaScript استدعاء دوال بشكلٍ متكرِّر. هذا الأمرُ مفيدٌ بشكلِ خاصّ في التعامل مع هياكل الشجرة tree structures، مثل ما تحصُلُ عليه في نموذج كائن المُستند DOM بالمُتصفّح. function countChars(elm) { if (elm.nodeType == 3) { // TEXT_NODE return elm.nodeValue.length; } var count = 0; for (var i = 0, child; child = elm.childNodes[i]; i++) { count += countChars(child); } return count; }هذا يُسلّط الضَوْء على مشكلةٍ مُحتملةٍ مع الدوال المجهولة: كيف يُمكن استدعاؤها بشكلِ متكرر إذا لم يكُن لديها اسم؟ تُتيحُ لكَ JavaScript تسمية تعبيرات دالَّة لهذا الغرض. يُمكنكَ استخدام تعبيرات تنفيذ الدالَّة مُباشرةً (IIFEs - Immediately Invoked Function Expressions) المُسمّاة على النحو التالي: var charsInBody = (function counter(elm) { if (elm.nodeType == 3) { // TEXT_NODE return elm.nodeValue.length; } var count = 0; for (var i = 0, child; child = elm.childNodes[i]; i++) { count += counter(child); } return count; })(document.body);الاسم المُقدّم إلى تعبير دالّة على النحو الوارد أعلاه إنَّما هو متاحٌ فقط لنطاقِ الدالّة نفسها. يَسمحُ هذا بمزيدِ من التحسينات تُنفَّذ من قِبَل المُحرِّك وتعليمات برمجيَّة أكثرُ قابليَّة للقراءة على حدٍّ سواء. يظهر الاسم أيضًا في المُصَحِّح debugger وبعض stack trace التي يمكن أن تُوفِّر لكَ الوقت. لاحظ أن دوالّ JavaScript هي نفسها كائنات ويُمكنكَ إضافة أو تغيير خصائص بها تمامًا مثل الكائنات الّتي تطرَّقنا إليها في جُزء الكائنات. الكائنات المُخصَّصَةمُلاحظة: للاطّلاع على نقاش أكثر تفصيلًا عن البرمجة الشيئيَّة في JavaScript، انظر مُقدِّمة إلى JavaScript الشيئيّة. في البرمجة الشيئيّة الكلاسيكيّة، الكائنات هي مجموعات من بيانات ووظائف تعملُ على تلك البيانات. JavaScript هي لغة النموذج القائم والتي لا تحتوي على فئات مثل تِلكَ التي توجد في C++ أو Java. (هذا الامرُ مُربِك أحيانًا للمبرمجين مِمَّن اعتادوا على لغات تحتوي على فئات.) بدلًا من ذلك تَستَخدِم JavaScript الدوال كفئات. لنعتبر أن هُناك كائن عبارة عن شخص Person لديه حقلي الاسم الأول والاسم الأخير. هُناك نوعان من الطرق التي من خلالها قد يتمّ عرض الاسم: كما "الأوَّل الأخير" أو "الأخير، الأوَّل". هذه طريقة لفعل ذلك باستخدام الدوال والكائنات التي ناقشناها سابقًا: function makePerson(first, last) { return { first: first, last: last }; } function personFullName(person) { return person.first + ' ' + person.last; } function personFullNameReversed(person) { return person.last + ', ' + person.first; } s = makePerson("Simon", "Willison"); personFullName(s); // "Simon Willison" personFullNameReversed(s); "Willison, Simon"هذه الطريقة تعمل ولكنَّها سيِّئة جدًا. ينتهي بكَ الأمر مع العشرات من الدوال في مساحتك العامَّة global namespace. ما نحتاجه حقًا هو وسيلة لإرفاق دالَّة بكائن. حيثُ أنَّ الدوال هي كائنات، هذا أمر سهل: function makePerson(first, last) { return { first: first, last: last, fullName: function() { return this.first + ' ' + this.last; }, fullNameReversed: function() { return this.last + ', ' + this.first; } }; } s = makePerson("Simon", "Willison") s.fullName(); // "Simon Willison" s.fullNameReversed(); // "Willison, Simon"هُناك شيء في هذه الجُمل التعليميَّة لم نَرَ من قبل: الكلمة المحجوزة this. تُستَخدَم this داخل الدالَّة وتُشير إلى الكائن الحالي. ما يُعنيه ذلك بالتحديد أنه يتمّ التعيين نِتاجًا عن الطريقة التي قُمتَ باستدعاء الدالَّة بها. إذا قمت باستدعائها باستخدام تأشير النقطة أو تأشير القوس في كائن، يُصبِح هذا الكائن this. إذا لم يتمّ استخدام تأشير النقطة dot notation للاستدعاء، تُشير this إلى الكائن العام global object. لاحظ أن this هي سبب مُتكرِّر للأخطاء. على سبيل المثال: s = makePerson("Simon", "Willison"); var fullName = s.fullName; fullName(); // undefined undefinedعندما نستدعي ()fullName وحدها، من دون استخدام ()s.fullName، فإنَّ هذا مُقيَّد بالنطاق العام global scope. وبما أنَّه لا توجد مُتغيِّرات عامَّة global variables تُسمَّى first أو last فإنَّنا نحصل على نوع undefined لكلِّ واحد منهما. يُمكننا الاستفادة من الكلمة المحجوزة this لتحسين دالَّة makePerson: function Person(first, last) { this.first = first; this.last = last; this.fullName = function() { return this.first + ' ' + this.last; }; this.fullNameReversed = function() { return this.last + ', ' + this.first; }; } var s = new Person("Simon", "Willison");قدَّمنا كلمة محجوزة أُخرى: new. ترتبط new ارتباطًا وثيقًا بـ this. ما تفعله هو أنَّها تخلُق كائن فارغ جديد تمامًا، ثم تدعو الدالَّة المُحدَّدة ويتمّ تعيين this لهذا الكائن الجديد. لاحظ أنَّ الدالَّة المُحدَّدة بواسطة this لا تُرجِع قيمة ولكنَّها فقط تقوم بتعديل كائن this. تُرجِع new كائن this إلى موقع الاستدعاء. يُطلَق على الدوال المُصمَّمة ليتمّ استدعاؤها بواسطة new دوال المُنشِئ. مُمارسة شائعة هي كتابة تلك الدوال بأحرف كبيرة كتذكير لاستدعائهم بواسطة new. لا يزال لدى الدالَّة المُحسَّنة نفس المأزق مع استدعاء ()fullName وحدها. بدأت كائنات Person تُصبِح أفضل ولكن لا تزال هُناك بعض الحوافّ السيِّئة لديها. في كل مرة نقوم بإنشاء كائن Person جديد فنحن نقوم بخلق كائني دالَّة جديدين به كذلك - ألن يكون أفضل لو كانت هذه التعليمات البرمجيَّة مُشتَرَكة؟ function personFullName() { return this.first + ' ' + this.last; } function personFullNameReversed() { return this.last + ', ' + this.first; } function Person(first, last) { this.first = first; this.last = last; this.fullName = personFullName; this.fullNameReversed = personFullNameReversed; }هذا أفضل: نقومُ بخلق دوال الوظيفة مرَّة واحدة فقط، ونُعيِّنُ مراجع لهم داخل المُنشئ. هل بإمكاننا فعل ما هو أفضل من ذلك؟ الجواب هو نعم: function Person(first, last) { this.first = first; this.last = last; } Person.prototype.fullName = function() { return this.first + ' ' + this.last; }; Person.prototype.fullNameReversed = function() { return this.last + ', ' + this.first; };Person.prototype هو كائن مُشتَرَك من قِبَل كافَّة نماذج Person. يُشكِّلُ هذا الكائن جُزءًا من سلسلة بحث (لها اسم خاص وهو "سلسلة النموذج" prototype chain): متى حاولتَ الوصول إلى خاصيَّة غير مُعيَّنة في Person، سوف تتحقَّق JavaScript من Person.prototype لترى ما إذا كانت هذه الخاصّيّة موجودة هناك بدلًا من ذلك. نتيجة لذلك، أي شيء مخصَّص لـ Person.prototype يُصبِح متاحًا لجميع النماذج من هذا المُنشئ عبر كائن this. هذه أداة قويَّة بشكلٍ لا يُصدَّق حيثُ أنَّ JavaScript تُتيحُ لكَ تعديل نموذج شيء في أيّ وقت في بَرنامجك، ممَّا يُعني أنَّه يُمكنكَ زيادة وظائف إضافيَّة لكائنات موجودة في وقت التَّشغيل: s = new Person("Simon", "Willison"); s.firstNameCaps(); // TypeError on line 1: s.firstNameCaps is not a function Person.prototype.firstNameCaps = function() { return this.first.toUpperCase() }; s.firstNameCaps(); // "SIMON"من المُثير للاهتمام أنَّهُ يُمكنكَ أيضًا إضافة أشياء إلى النموذج الخاصّ بالكائنات المُدمجة في JavaScript. دعونا نُضيف وظيفة إلى سلسلة تقوم بإرجاع هذه السلسلة معكوسة: var s = "Simon"; s.reversed(); // TypeError on line 1: s.reversed is not a function String.prototype.reversed = function() { var r = ""; for (var i = this.length - 1; i >= 0; i--) { r += this[i]; } return r; }; s.reversed(); // nomiSتعمل الطَّريقة الجديدة حتَّى مع حرفيَّات السلسلة string literals "This can now be reversed".reversed(); // desrever eb won nac sihTكما ذكرتُ سالِفًا، يُشكِّل النموذج جزءًا من سلسلة. جذر تلك السلسلة هو Object.prototype والذي من وظائفه ()toString - تلك هي الوظيفة التي يتمّ استدعاؤها عندما تُحاول تمثيل كائن كسلسلة. يُعتبَر هذا مفيدًا من أجل تصحيح كائنات Person: var s = new Person("Simon", "Willison"); s; // [object Object] Person.prototype.toString = function() { return '<Person: ' + this.fullName() + '>'; } s; // "<Person: Simon Willison>"أتذكُرُ كيف احتَوَت ()avg.apply على مُعامِل أوَّل فارغ null؟ يُمكننا إعادة النَّظر في ذلك الآن. المُعامِل الأول في ()apply هو الكائن الذي يجب أن يُعامَل على أنَّهُ 'this'. هذا تنفيذٌ تافه لـ new على سبيل المثال: function trivialNew(constructor, ...args) { var o = {}; // Create an object constructor.apply(o, args); return o; }لا يُعتَبرُ هذا نُسخة طبق الأصل من new لأنها لم تقم بإعداد سلسلة النَّموذج (سيكون من الصَّعب التَّوضيح). هذا ليس شيئًا تستخدمه في كثيرٍ من الأحيان ولكن من المفيد أن تعرف عنه. يُطلَق على مُقتطف ...args (بما في ذلك علامات الحذف) "المُعامِلات المُتبقّية" rest arguments - كما يُوحِي اسمها فهي تحتوي على بقيَّة المُعامِلات. استدعاء var bill = trivialNew(Person, "William", "Orange");يُعادِل تقريبًا var bill = new Person("William", "Orange");لدى ()apply دالَّة أخت اسمها call، والتي أيضًا تُتيحُ لكَ تعيين this ولكنَّها تأخذ قائمة موسَّعة من المُعامِلات بدلًا من مصفوفة. function lastNameCaps() { return this.last.toUpperCase(); } var s = new Person("Simon", "Willison"); lastNameCaps.call(s); // Is the same as: s.lastNameCaps = lastNameCaps; s.lastNameCaps();الدوالّ الداخليّةتعريفات دالَّة JavaScript مسموحٌ بها داخل دوال أخُرى. لقد رأينا هذا من قبل مع دالَّة ()makePerson. هُناك تفصيل مهمّ في الدوال المُتداخلة في JavaScript وهو أنَّه يُمكِنُها الوصول إلى مُتغيِّرات في نِطَاق الدالَّة الأم: function betterExampleNeeded() { var a = 1; function oneMoreThanA() { return a + 1; } return oneMoreThanA(); }يوفِّر هذا قدرًا كبيرًا من الفائدة في كتابة تعليمات برمجيَّة أكثر صيانة. إذا اعتَمَدَتْ دالَّة على واحدة أو اثنتين من الدوال الأُخرى غير المُفيدة لأي جُزء من تعليماتك البرمجيَّة، يُمكنكَ إدخال تلك الدوال ذات المنفعة في الدالَّة التي سيتمّ استدعاؤها من مكان آخر. يُحافظ هذا على عدد من الدوال التي هي في النطاق العام، وهذا دائمًا شيءٌ جيد. يُعتبر هذا عدَّاد كبيرة لإغراء المُتغيِّرات العامَّة global variables. عند كتابة تعليمات برمجيَّة معقَّدة غالبًا ما يكون مُغريًا استخدام مُتغيِّرات عامَّة لتبادُل القيم بين دوالّ مُتعدِّدة - الأمر الذي يؤدِّي إلى تعليمات برمجيِّة من الصعب صيانتها. يُمكنُ للدوالّ المُتداخلة مُشاركة المُتغيِّرات الموجودة في الدالَّة الأم، لذلك يُمكنكَ استخدام هذه الآليَّة لتجميع دالَّتين معًا متى كان هذا منطقيَّا دون تلويث مساحتُكَ العامَّة – ‘محليّات عامَّة’ إذا أردتَ أن تُطلِق عليها ذلك. ينبغي استخدام هذا الأسلوب مع الحذر، إلَّا أنَّ حوذته قُدرة مُفيدة. الإغلاقيقودنا هذا إلى واحدة من التجريدات الأكثر قوّة التي بإمكان Javascript تقديمها - ولكن أيضًا الأكثر تعريضًا للارتباك. ماذا تفعل هذه التعليمات البرمجيَّة؟ function makeAdder(a) { return function(b) { return a + b; }; } var x = makeAdder(5); var y = makeAdder(20); x(6); // ? y(7); // ?يجب أن يكون اسم دالَّة makeAdder قد أوضَح كل شيء: يقوم بخلق دوال 'adder' جديدة، تلك الدوال التي عند استدعائها بواسطة مُعامِل تقوم باضافته إلى المُعامِل الذي تم إنشائهم بواسطته. ما يحدث هُنا هو إلى حدٍّ كبير نفس ما كان يحدث مع الدوال الداخليَّة في وقتٍ سابق: للدالَّة المُعرَّفة داخل دالَّة أخرى حقّ الوصول إلى مُتغيِّرات الدالَّة الخارجيَّة. الفرقُ الوحيدُ هُنا هو أن الدالَّة الخارجيَّة قد عادت، وبالتالي الحس السليم يهدي إلى أن مُتغيِّراتها المحليَّة لم تعد موجودة. لكنها لا تزال موجودة - لولاها دوال adder ما كانت قادرة على العمل. ما هو أكثر من ذلك، هناك نوعان من "نسخ" مختلفة من المُتغيِّرات المحليّة الخاصَّة بـ makeAdder - نُسخة بها a هو 5 ونُسخة بها a هو 20. وبُناءً على ذلك فإن نتيجة استدعاءَات الدالَّة تلك هي على النحو التالي: x(6); // returns 11 y(7); // returns 27إليكَ ما يحدُث فعليًّا. عندما تقوم Javascript بتنفيذ دالَّة يتمّ إنشاء كائن 'نطاق' للاحتفاظ بالمُتغيِّرات المحليَّة التي تم إنشاؤها داخل تلك الدالَّة. يتمّ تهيئتها مع أيّ مُتغيَّر يتمّ ارساله كعامِل دالَّة مُتغيِّر. يُشبه هذا الكائن العام الذي يحتوي على جميع المُتغيِّرات والدوال العامَّة، ولكن هُناك مع بعض الاختلافات الهامَّة: أوَّلُها، يتمَّ إنشاء كائن نطاق جديد تمامًا في كل مرة تبدأ دالَّة بالتنفيذ. ثانيها، لا يُمكن الوصول المُباشِر إلى كائنات النطاق تلك من خلال جُمل Javascript البرمجيَّة الخاصَّة بك، على عكس الكائن العام (الذي يُمكن الوصول إليه كـ this ويُمكن الوصول إليه في المُتصفِّحات كـwindow). على سبيل المثال ليس هُناك آليَّة لتكرار خصائص كائن النِطاق الحالي. لذلك عندما يتم استدعاء makeAdder، يتمّ إنشاء كائن نطاق مع خاصيَّة واحدة: a، والذي هو المُعامِل الذي تمّ تمريره إلى دالَّة makeAdder. تُعيد بعد ذلك makeAdder دالَّة تمّ إنشاؤها حديثًا. في هذه المرحلة عادةً يقوم جامع القُمامة في JavaScript بتنظيف كائن النطاق الذي تمّ خلقه لـ makeAdder، ولكن الدالًّة المُعادة تُحافظ على مرجع إلى كائن النطاق هذا. نتيجة لذلك، لن يكون كائن النطاق القمامة مُجمَّعة إلى أن لا يكون هُناك أيَّة مراجع إلى كائن الدالَّة التي أعادتها makeAdder. تُكوِّن كائنات النطاق سلسلة تُسمَّى سلسلة نطاق scope chain، على غرار سلسلة النَّموذج المُستخدمة من قبل نظام كائن JavaScript. الإغلاق هو مزيجٌ من دالَّة وكائن النِّطاق الذي بِهِ تمّ إنشاء تلك الدالَّة. يُمكِّنُكَ الإغلاق من حفظ الحالة - كما أنَّه كثيرًا ما يمكن استخدامه بدلًا من الكائنات. يُمكِن العثور على عدَّة مُقدِّمات ممتازة للإغلاق هُنا. تسريبات الذَّاكرةأحد الآثار الجانبيّة المؤسفة للإغلاق هو أنَّه يجعل من السَّهل تسرب الذاكرة في Internet Explorer. Javascript هي لغة تجميع البيانات المُهملة - تُخصَّص ذاكرة للكائنات عند إنشائها ويتم استعادة تلك الذَّاكرة من قِبَل المُتصفِّح عندما لا تتبقَّى مراجع إلى كائن. يتم التعامل مع الكائنات التي توفّرها البيئة المضيفة عن طريق تلك البيئة. تحتاج مُستضيفات المُتصفِّح إلى إدارة عدد كبير من الكائنات التي تمثل صفحة HTML المُقدَّمة ألا وهي كائنات الـ DOM. الأمر متروك للمُتصفِّح لإدارة تخصيص واسترداد هذه الكائنات. يستخدم Internet Explorer لهذا آلية جمع القمامة الخاصَّة به، بعيدًا عن الآليَّة المستخدمة لـ JavaScript. إنَّ التفاعل بين الآليَّتين هو ما قد يتسبِّب في تسرُّب الذَّاكرة. يحدث تسرُّب الذاكرة في IE أي وقت يتمّ تشكيل مرجع دائري بين كائن JavaScript وكائن أصلي. تأمَّل ما يلي: function leakMemory() { var el = document.getElementById('el'); var o = { 'el': el }; el.o = o; }تخلُق المراجع الدائريَّة المُشكَّلة بالأعلى تسرُّب للذَّاكرة. لن يقوم IE بتحرير الذَّاكرة المُستخدمة من قِبَل el وo حتَّى يتمّ إعادة تشغيل المُتصفِّح تمامًا. من المُرجَّح ألّا تُلاحَظ الحالة المذكورة أعلاه. يُصبح تسرُّب الذَّاكرة مصدر قلق حقيقي فقط في التطبيقات طويلة التشغيل أو التطبيقات التي تُسرِّب قدرًا كبيرًا من الذَّاكرة بسبب هياكل البيانات الكبيرة أو أنماط التسرُّب داخل الحلقات. نادرًا ما تكون التسريبات واضحة بهذا الشَّكل - في كثيرٍ من الأحيان يمكن أن يكون لهيكل البيانات المسرَّبة عدة طبقات من المراجع تقومُ بالعتيم على مرجع مُعاد. يجعلُ الإغلاق من السَّهل خلق تسرُّب ذاكرة دون قصد. انظر إلى التعليمات البرمجيَّة هذه: function addHandler() { var el = document.getElementById('el'); el.onclick = function() { el.style.backgroundColor = 'red'; }; }تقوم التعليمات البرمجيَّة أعلاه بتحويل العنصر إلى أحمر عند النقر عليه. كما أنَّها أيضًا تخلُق تسرُّب ذاكرة. لماذا؟ لأن الإشارة إلى el قُبِضَت دون قصد في الإغلاق الذي تمَّ إنشاؤه للدالَّة الداخليَّة المجهولة. يخلُق هذا مرجعًا دائريًّا بين كائن JavaScript (الدالَّة) وكائن أصلي (el). هُناك عدد من الحلول لهذه المشكلة. أبسطُها هو عدم استخدام مٌتغيِّر el: function addHandler(){ document.getElementById('el').onclick = function(){ this.style.backgroundColor = 'red'; }; }المُثير للدَّهشة أن هُناك خدعة لكسر المراجعِ الدائريَّة تُقدَّم بواسطة الإغلاق، هذه الخُدعة هي إضافةُ إغلاقٍ آخر: function addHandler() { var clickHandler = function() { this.style.backgroundColor = 'red'; }; (function() { var el = document.getElementById('el'); el.onclick = clickHandler; })(); }يتمُّ تنفيذ الدالّة الداخليّة على الفور وتُخفي محتوياتها عن الإغلاق الذي تمَّ انشاؤه باستخدام clickHandler. خدعة أُخرى جيّدة لتجنب الإغلاق هي كسر المراجعِ الدائريَّة خلال حدث window.onunload. سوف تقوم العديد من مكتبات الحدث بتنفيذِ ذلك بدلًا عنك. لاحظ عمل بذلك يقوم بتعطيل ذاكرة التخزين المؤقت back-forward في فيرفُكس، لذلك يجبُ عليكَ أن لا تُسجِّل مُستمع unload في فَيرفُكس، إلا إذا كان لديك أسباب أخرى للقيام بذلك.
×
×
  • أضف...