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

البحث في الموقع

المحتوى عن 'البرمجة بلغة روبي'.

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المحتوى


التصنيفات

  • الإدارة والقيادة
  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • السلوك التنظيمي في المؤسسات
  • عالم الأعمال
  • التجارة والتجارة الإلكترونية
  • نصائح وإرشادات
  • مقالات ريادة أعمال عامة

التصنيفات

  • مقالات برمجة عامة
  • مقالات برمجة متقدمة
  • PHP
    • Laravel
    • ووردبريس
  • جافاسكربت
    • لغة TypeScript
    • Node.js
    • React
    • Vue.js
    • Angular
    • jQuery
    • Cordova
  • HTML
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • لغة C#‎
    • ‎.NET
    • منصة Xamarin
  • لغة C++‎
  • لغة C
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • لغة Rust
  • برمجة أندرويد
  • لغة R
  • الذكاء الاصطناعي
  • صناعة الألعاب
  • سير العمل
    • Git
  • الأنظمة والأنظمة المدمجة

التصنيفات

  • تصميم تجربة المستخدم UX
  • تصميم واجهة المستخدم UI
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب GIMP
    • كريتا Krita
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • مقالات DevOps عامة
  • خوادم
    • الويب HTTP
    • البريد الإلكتروني
    • قواعد البيانات
    • DNS
    • Samba
  • الحوسبة السحابية
    • Docker
  • إدارة الإعدادات والنشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
    • ريدهات (Red Hat)
  • خواديم ويندوز
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • شبكات
    • سيسكو (Cisco)

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح
  • مبادئ علم التسويق

التصنيفات

  • مقالات عمل حر عامة
  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • العمل الحر المهني
    • العمل بالترجمة
    • العمل كمساعد افتراضي
    • العمل بكتابة المحتوى

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

  • الأقسام
    • أسئلة البرمجة
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات

التصنيفات

  • كتب ريادة الأعمال
  • كتب العمل الحر
  • كتب تسويق ومبيعات
  • كتب برمجة
  • كتب تصميم
  • كتب DevOps

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

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

  • بداية

    نهاية


المجموعة


النبذة الشخصية

تم العثور على 11 نتائج

  1. يحتوي كل برنامج على العديد من أنواع البيانات، إذ يجب أن تكون العمليات على البيانات بين نفس النوع من البيانات دومًا، مثل العمليات الرياضية على الأرقام، أو دمج السلاسل النصية معًا، ويمكن أن تكون هذه البيانات من مصادر خارجية، مثل لوحة المفاتيح أو استجابة لواجهة برمجة تطبيقات API أو قاعدة بيانات، إذ سنحتاج في هذه الحالة إلى التحويل بين أنواع البيانات قبل تنفيذ العمليات عليها، ولذلك الغرض توفر لغة روبي Ruby العديد من الطرق لتحويل القيم من نوع بيانات إلى آخر، لذلك سنتعرف في هذا المقال على طرق تحويل السلاسل النصية إلى أعداد، والكائنات إلى سلاسل نصية، والسلاسل النصية إلى مصفوفات، والتحويل بين السلاسل النصية والرموز. تحويل السلاسل النصية إلى أعداد توفر روبي التابعين to_i و to_f لتحويل السلاسل النصية إلى أعداد، إذ يحوّل to_i السلسلة النصية إلى عدد صحيح، ويحول التابع to_f السلسلة النصية إلى عدد عشري: "5".to_i # 5 "55.5".to_i # 55 "55.5".to_f # 55.5 لتوضيح ذلك، سننشئ برنامجًا صغيرًا يطلب من المستخدم إدخال عددين ويعرض مجموعهما، لذا ننشئ ملف جديد نسميه adder.rb ونضيف إليه الشيفرة التالية: print "What is the first number? " first_number = gets.chop print "What is the second number? " second_number = gets.chop sum = first_number + second_number print sum عند تشغيل البرنامج: $ ruby adder.rb سنحصل على الإجابة التالية: What is the first number? 5 What is the second number? 5 55 نلا حظ أن مجموع العدد 5 مع 5 هو 55 وهي نتيجة خاطئة، والسبب في ذلك أن القيم المُدخلة من لوحة المفاتيح لم ترسل العدد 5 بل أرسلت الحرف "5"، أي أن البرنامج ينظر إلى كل من العددين المدخلين على أنهما سلاسل نصية، وعند جمع السلسلتين النصين "5" و "5" سنحصل على السلسلة النصية الجديدة "55" وهي النتيجة التي ظهرت، ولحل المشكلة يجب تحويل المدخلات إلى أعداد أولًا قبل تنفيذ عملية الجمع، ويمكننا ذلك باستخدام التابع to_f على النحو التالي: print "What is the first number? " first_number = gets.chop print "What is the second number? " second_number = gets.chop # convert strings to numbers first_number = first_number.to_f second_number = second_number.to_f sum = first_number + second_number print sum ننفذ البرنامج مجددًا: $ ruby adder.rb لنلاحظ جمع الأعداد حسابيًا وإظهار النتيجة الصحيحة: What is the first number? 5 What is the second number? 5 10.0 عند محاولة تحويل سلسلة نصية غير قابلة للتحويل إلى عدد باستخدام أحد التابعين to_i و to_f على النحو التالي: "123-abc".to_i سيكون الخرج: 123 نلاحظ تحويل السلسلة النصية "123-abc" إلى العدد الصحيح 123 باستخدام التابع to_i، إذ يتوقف ذلك التابع عندما يصل إلى أول محرف غير رقمي ويعيد النتيجة. يستغل مطورو الويب هذه الخاصية في روبي لإنشاء روابط URL مثل 15-sammy-shark، إذ يدل الرقم 15 في ذلك النص على معرف داخلي للبحث ضمن سجل قاعدة البيانات، أما القسمsammy-shark هو وصف نصي للرابط ليسهل قراءته، وعند تحويل القيمة 15-sammy-shark إلى عدد صحيح باستخدام التابع to_i، سيتجاهل التابع الجزء النصي -sammy-shark ويعيد العدد الصحيح 15 الذي يمكن استخدامه للبحث ضمن سجل قاعدة البيانات، وفيما يلي مثال آخر عن تحويل سلسلة نصية غير عددية: "abc".to_i سيكون الخرج: 0 نلاحظ أن التابع to_i يعيد القيمة 0، إذ لا يمكن تحويل أي من المحارف في تلك السلسلة النصية إلى عدد صحيح، وقد يسبب ذلك مشاكل فإذا أدخل المستخدم بإدخال القيمة "abc" ضمن برنامج ما وحولنا هذه القيمة إلى عدد صحيح ثم أجرينا عملية القسمة على ذلك العدد سيحدث خطأ لعدم إمكانية القسمة على الصفر، ولحل تلك المشكلة توفّر روبي طريقةً أخرى لتحويل البيانات إلى أعداد باستخدام أحد التابعينInteger أوFloat للتحويل: Integer("123") والخرج: 123 عند محاولة تحويل قيمة غير صالحة للتحويل باستخدام التابع Integer سيرمي خطأ في حال لم تكن كل السلسلة النصية قابلة للتحويل: Integer("123abc") سيكون الخرج في هذه الحالة على النحو التالي: ArgumentError: invalid value for Integer(): "123abc" نستفيد من ذلك الخطأ لإظهار رسالة للمستخدم مثلًا نطلب منه إدخال قيمة عددية صحيحة، مما يضمن سلامة البيانات المُدخلة وأن القيمة التي أدخلها المستخدم هي المقصودة. سنتعرف في الفقرة القادمة على طريقة تحويل أنواع أخرى من البيانات إلى سلاسل نصية. تحويل البيانات إلى سلاسل نصية توفر لغة روبي التابع to_s لتحويل أي نوع من البيانات إلى سلسلة نصية: 25.to_s # "25" (25.5).to_s # "25.5" ["Sammy", "Shark"].to_s # "[\"Sammy\", \"Shark\"]" نحتاج غالبًا قبل عرض البيانات للمستخدم إلى تحويل البيانات إلى سلاسل نصية، ففي المثال التالي سنحاول طباعة قيمة من نوع سلسلة نصية وقيمة عددية. نبدأ بإنشاء ملف بالاسم calories.rb يحتوي على التالي: user = "Sammy" calories = 100 print "Congratulations, " + user + "! You just burned " + calories + " calories during this workout." أضفنا قيم المتغيرات في المثال السابق يدويًا، ولكن عادة ما سنستقبل تلك القيم من مصدر خارجي مثل مدخلات المستخدم أو من قاعدة البيانات أو غيرها، والآن ننفذ البرنامج: $ ruby calories.rb ليظهر لنا رسالة الخطأ التالية: ... TypeError: no implicit conversion of Integer into String (TypeError) لا يمكن إضافة المتغير calories إلى باقي النص الذي نحاول طباعته لأنه يحتوي على قيمة من نوع عدد صحيح لا يمكن تحويلها إلى سلسلة نصية بإضافة علامات تنصيص حولها بل باستخدام التابع to_s قبل دمجها مع بقية النص المطبوع. لحل المشكلة: نعدّل السطر الذي يحتوي على النتيجة ونحول قيمة المتغير calories إلى سلسلة نصية باستخدام التابع to_s على النحو التالي: user = "Sammy" calories = 100 print "Congratulations, " + user + "! You just burned " + calories.to_s + " calories during this workout." نُنفذ البرنامج مجددًا ونلاحظ اختفاء الخطأ السابقة وظهور النتيجة المطلوبة: Congratulations, Sammy! You just burned 100 calories during this workout. يمكن أيضًا استخدام خاصية استيفاء النص interpolation المتوفرة في لغة روبي، والتي تحول الكائنات إلى سلاسل نصية تلقائيًا دون الحاجة لأي عمليات تحويل إضافية، لنحاول استخدامها في المثال السابق على النحو التالي: print "Congratulations, #{user}! You just burned #{calories} calories during this workout." ننفذ البرنامج مرةً أخرى ونلاحظ ظهور النتيجة نفسها، إذ توفر جميع الكائنات في لغة روبي التابع to_s الذي يحول الكائن إلى سلسلة نصية بطريقة موحدة، وفي حال أردنا التحويل بطريقة مختلفة يمكننا كتابة شيفرة مخصصة لذلك. توفر جميع الكائنات في لغة روبي التابع inspect الذي يفيد خلال مرحلة التطوير في عملية تنقيح الأخطاء، إذ يعيد ذلك التابع نفس النتيجة التي يعيدها التابع to_s مع بيانات أكثر تفصيلًا عن الكائن، لذا يقتصر استخدام ذلك التابع في مرحلة التطوير فقط، ويمكن استخدامه مع التابع puts لعرض قيم المتغيرات أثناء تطوير البرنامج. سنتعرف في الفقرة القادمة على طريقة تحويل سلسلة نصية إلى مصفوفة. تحويل السلاسل النصية إلى مصفوفات يمكن تحويل أي سلسلة نصية إلى مصفوفة باستخدام التابع split على النحو التالي: "one two three".split ويكون الخرج على النحو التالي: ["one", "two", "three"] يمكن تحديد المحرف الذي نريد استخدامه مثل محدد لفصل السلسلة النصية إلى عناصر بتمريره بمثابة معامل إلى التابع split. سنحوّل في المثال التالي سلسلة نصية تحتوي على قيم مفصولة بفواصل إلى مصفوفة ثم سنرتبها ونطبع قيمة كل عنصر منها على الشاشة، ونبدأ بإنشاء ملف بالاسم "data_import.rb" يحتوي على الشيفرة التالية: data = "Tiger,Great White,Hammerhead,Whale,Bullhead" # Convert data to an array by splitting on commas sharks = data.split(",") # Sort the sharks alphabetically sharks = sharks.sort! # Print out the sharks by iterating through the array sharks.each{|shark| puts shark } ننفذ البرنامج: $ ruby data_import.rb لنحصل على الخرج التالي: Bullhead Great White Hammerhead Tiger Whale نلاحظ مدى قوة المصفوفات في لغة روبي والاستخدامات المتعددة لها. سنتعلم في الفقرة التالية طريقة التحويل بين السلاسل النصية والرموز. التحويل بين السلاسل النصية والرموز يمكن تحويل رمز إلى سلسلة نصية لنتمكن من طباعته، وقد نحتاج أحيانًا لتحويل سلسلة نصية إلى رمز لاستخدامه للبحث ضمن جدول Hash، إذ يمكن للتابع to_s تحويل الرموز إلى سلاسل نصية مباشرةً: :language.to_s ويكون الخرج: "language" يمكننا التعديل على الشكل النهائي للسلسلة النصية المُعبرة عن الرمز، ففي المثال التالي سنحول الرمز first_name: إلى السلسلة النصية الأوضح والأسهل بالقراءة "First name" كالتالي: string = :first_name.to_s # replace underscore with a space and capitalize string = string.gsub("_"," ").capitalize يمكن تحويل السلاسل النصية إلى رموز باستخدام التابع to_sym كما يلي: "first_name".to_sym وبذلك يكون الخرج: :first_name لتحويل السلسلة النصية "First name" إلى الرمز first_name: مجددًا، يجب أولًا تحويل جميع الأحرف إلى الحالة الصغيرة واستبدال المسافات بشرطات سفلية على النحو التالي: string = "First name" # replace spaces with underscores and convert to lowercase string = string.gsub(" ","_").downcase # Convert to symbol symbol = string.to_sym نحتاج كثيرًا للتحويل بين الرموز والسلاسل النصية، سواءٌ لعرض رمز ما بشكلٍ سهل القراءة للمستخدم أو لاستخدام السلسلة النصية للبحث عن مفتاح محدد ضمن جدول Hash الذي يستخدم الرموز من أجل مفاتيحه. الخاتمة تعرفنا في هذا المقال على طرق تحويل بعض أنواع البيانات الأساسية إلى أنواع بيانات أخرى باستخدام التوابع التي توفرها لغة روبي ضمن الكائنات، مثل تحويل الأرقام إلى سلاسل نصية، والسلاسل النصية إلى مصفوفات، والتحويل بين الرموز والسلاسل النصية، إذ من المهم التعرف على طرق التحويل تلك للتعامل مع أنواع البيانات المختلفة وتنفيذ العمليات عليها. ترجمة -وبتصرف- للمقال How To Convert Data Types in Ruby لصاحبه Brian Hogan. اقرأ أيضًا المقال السابق: توابع المصفوفات في لغة روبي السلاسل النصية في لغة روبي دليلك الشامل إلى أنواع البيانات
  2. تسمح المصفوفات arrays بتمثيل قائمة من البيانات معًا وتخزينها ضمن متغير واحد لنتمكن من إجراء العمليات المختلفة على تلك البيانات، مثل فرزها أو إزالة العناصر المكررة منها، أو عكس ترتيبها، أو استخراج أجزاء من المصفوفة، أو البحث ضمنها عن بيانات محددة، ويمكننا أيضًا تحويل المصفوفة إلى سلسلة نصية أو إلى مصفوفة بيانات أخرى أو دمج عناصر المصفوفة معًا في قيمة واحدة. سنتعرف في هذا المقال على بعض التوابع التي توفرها لغة روبي للتعامل مع البيانات ضمن المصفوفات. سنلاحظ انتهاء أسماء بعض تلك التوابع بعلامة تعجب !، مما يشير أن هذا التابع سيعدل على قيمة المصفوفة الأصلية وقد يرمي استثناءات، ويوجد غالبًا تابع مقابل بنفس الاسم لمعظم التوابع الموجودة ضمن المصفوفات ولكن ينتهي بهذه اللاحقة. يوجد كذلك توابع أخرى تنتهي بعلامة استفهام ? وهي توابع تعيد قيمة بوليانية منطقية تشير، ويُعد هذا الأسلوب شائعًا في تسمية التوابع ضمن روبي، وسنبدأ بالتعرف على توابع المصفوفات بدايةً من خلال عدة طرق للوصول إلى العناصر ضمن المصفوفة. الوصول إلى عنصر من المصفوفة تعرفنا في المقال السابق على طريقة الوصول لعنصر محدد ضمن المصفوفة باستخدام رقم الفهرس الخاص به والذي يبدأ من الصفر على النحو التالي: sharks = ["Tiger", "Great White", "Hammerhead", "Angel"] sharks[0] # "Tiger" sharks[1] # "Great White" sharks[-1] # "Angel" وتعرفنا أيضًا على كل من التابعين first و last واللذان يمكن استخدامهما للحصول على أول وآخر عنصر من المصفوفة: sharks = ["Tiger", "Great White", "Hammerhead", "Angel"] sharks.first # "Tiger" sharks.last # "Angel" وعند الوصول لعنصر غير موجود ضمن المصفوفة، سنحصل على القيمة nil، وإذا أردنا أن ينتج عن تلك العملية خطأ فيمكن استخدام التابع fetch: sharks.fetch(42) ليكون الخرج على النحو التالي: IndexError: index 42 outside of array bounds: -4...4 ويمكن تحديد قيمة افتراضية للعناصر غير الموجودة بدلًا من رمي خطأ، مثل تمرير تلك القيمة الافتراضية مثل وسيط ثانٍ للتابع fetch: sharks.fetch(42, "Nope") # "Nope" سنتعرف في الفقرة التالية على طريقة الحصول على عدة عناصر من المصفوفة معًا. استخراج عدة عناصر من المصفوفة قد نحتاج أحيانًا للحصول على عدة عناصر من المصفوفة معًا بدلًا من عنصر واحد فقط، ويمكننا ذلك عبر تحديد رقم الفهرس لأول عنصر نريده من المصفوفة، ثم تمرير عدد العناصر التي نريد استخراجها بدءًا من ذلك العنصر، لتُنشأ مصفوفةٌ جديدةٌ تحتوي على تلك العناصر المحددة، فمثلًا يمكن استخراج العنصرين المتوسطين من المصفوفة sharks على النحو التالي: sharks = ["Tiger", "Great White", "Hammerhead", "Angel"] sharks[1,2] # ["Great White", "Hammerhead"] نبدأ من الفهرس رقم 1 الذي يحتوي على قيمة "Great White" ونحدد بعدها عدد العناصر التي نريد استخراجها وهو 2، وبذلك تُنشأ مصفوفة جديدة تحتوي على "Great White" و "Hammerhead". يمكن استخدام التابع slice لإجراء نفس العملية: sharks = ["Tiger", "Great White", "Hammerhead", "Angel"] sharks.slice(1,2) # ["Great White", "Hammerhead"] يعيد التابع slice مصفوفةً جديدةً دون التعديل على المصفوفة الأصلية، ولكن إذا استخدمنا التابع !slice ستتغير قيمة المصفوفة الأصلية. يمكن أيضًا استخدام التابع take لاستخراج عدد محدد من العناصر بدءًا من بداية المصفوفة: sharks = ["Tiger", "Great White", "Hammerhead", "Angel"] sharks.take(2) # ["Tiger", "Great White"] قد نحتاج لاستخراج عنصر عشوائي من المصفوفة بدلًا من قيمة محددة، وسنتعرف على طريقة تنفيذ ذلك في الفقرة التالية. الحصول على عنصر عشوائي من المصفوفة قد نحتاج في بعض الحالات لاستخراج قيمة عشوائية لا على التعيين من مصفوفة ما، خصوصًا عند تطوير بعض الألعاب التي تعتمد على الحظ، إذ يمكننا تنفيذ ذلك بتخزين جميع الخيارات الممكنة ضمن مصفوفة واختيار إحداها بتوليد رقم فهرس عشوائي بين الرقم 0 ورقم آخر فهرس لآخر عنصر من المصفوفة. تتيح لك روبي طريقةً أسهل عبر التابع sample، الذي يعيد عنصرًا عشوائيًا من المصفوفة مباشرةً على النحو التالي: answers = ["Yes", "No", "Maybe", "Ask again later"] print answers.sample ويكون الخرج: Maybe يقبل التابع sample عددًا مثل وسيط أول، ويعيد مصفوفةً تحتوي على عدد محدد من العناصر العشوائية، فإذا كنا بحاجة لأكثر من عنصر عشوائي، يمكننا تمرير العدد المطلوب لذلك التابع كما يلي: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] sample = sharks.sample(2) print sample ليكون الخرج على النحو التالي: ["Whale", "Great White"] سنتعرف في الفقرة التالية على طرق البحث عن عناصر محددة داخل مصفوفة. البحث وتصفية عناصر المصفوفة يمكننا البحث عن عناصر محددة داخل مصفوفة بالمرور على عناصر تلك المصفوفة واحدًا تلو الآخر وفحص كل عنصر منها إلى أن نجد العنصر المطلوب، ولكن روبي توفر عدة توابع تُسهل عملية البحث تلك ضمن المصفوفات، إذ يمكن مثلًا التحقق ما إذا كان العنصر موجودًا ضمن المصفوفة باستخدام التابع ?include، الذي يعيد القيمة true في حال كان العنصر المحدد موجودًا: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] sharks.include? "Tiger" # true ["a", "b", "c"].include? 2 # false إذ يبحث التابع ضمن المصفوفة عن العنصر الذي يطابق القيمة المُمررة له تمامًا، أي لا يمكننا مثلًا البحث عن أجزاء من سلسلة نصية على النحو التالي: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] sharks.include? "Tiger" # true sharks.include? "tiger" # false sharks.include? "ti" # false يمكن حل المشكلة باستخدام التابع find، الذي يعيد أول عنصر يطابق الشرط المحدد داخل المصفوفة، فمثلًا للبحث عن أول عنصر يحتوي على الحرف a ضمن مصفوفة sharks، يمكن استخدام التابع each للمرور على كل عنصر بالترتيب والتوقف عند العثور على العنصر الأول المطابق لهذا الشرط كما يلي: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] result = nil sharks.each do |shark| if sharks.include? "a" result = shark break end end أو استخدام التابع find بدلًا من ذلك لتنفيذ نفس العملية: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] result = sharks.find {|item| item.include?("a")} print result ويكون الخرج: Hammerhead ينفذ التابع find التعبير البرمجي الممرر له على كل عنصر داخل المصفوفة، وفي حال كانت القيمة التي يعيدها ذلك التعبير البرمجي الممرر القيمة true، يوقف التابع find عملية المرور ويعيد تلك القيمة مباشرةً، وإذا لم يُعثر على أي عنصر يطابق الشرط المحدد يعيد القيمة nil. يعمل التابع select بطريقة مشابهة للتابع find ولكنه سيُنشئ مصفوفة جديدة تحتوي على جميع العناصر التي تطابق الشرط المحدد بدلًا من قيمة واحدة فقط على النحو التالي: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] results = sharks.select {|item| item.include?("a")} print results وتكون النتيجة على النحو التالي: ["Hammerhead", "Great White", "Whale"] يعيد التابع reject مصفوفةً جديدةً تحتوي على العناصر التي لا تطابق الشرط المحدد، ويمكن استخدامه لتصفية وإزالة العناصر التي لا نرغب بها من المصفوفة، فمثلًا يمكننا إزالة جميع العناصر التي تحتوي على الحرف a من المصفوفة كما يلي: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] results = sharks.reject {|item| item.include?("a")} print results ويكون الخرج: ["Tiger"] يعيد كلًا من التابعين select و reject مصفوفةً جديدةً دون تغيير قيمة المصفوفة الأصلية، ويمكن استخدام التابعين المقابلين !select و !reject في حال أردنا التعديل على قيمة المصفوفة الأصلية؛ أما التابع find_all فهو بديل للتابع selectولكن الفرق بأنه لا يوجد تابع مقابل له للتعديل على قيمة المصفوفة. سنتعرف في الفقرة التالية على طرق ترتيب عناصر المصفوفة. ترتيب عناصر المصفوفة نحتاج في كثير من الأحيان لترتيب بعض البيانات، مثل ترتيب قائمة من الأسماء أبجديًا، أو ترتيب بعض الأرقام من الأصغر إلى الأكبر، ومن التوابع التي تتعامل مع ترتيب العناصر ضمن المصفوفة هو التابع reverse، الذي يعكس ترتيب العناصر؛ فإذا كانت لدينا قائمة مرتبة من بيانات يمكن استخدام ذلك التابع بمثابة طريقة سريعة لعكس ترتيبها على النحو التالي: sharks = ["Angel", "Great White", "Hammerhead", "Tiger"] reversed_sharks = sharks.reverse print reversed_sharks ويكون الخرج: ["Tiger", "Hammerhead", "Great White", "Angel"] يعيد التابع reverse مصفوفةً جديدةً دون تغيير قيمة المصفوفة الأصلية، ويمكن استخدام التابع !reverse في حال أردنا تغيير قيمة المصفوفة الأصلية. لا يكفي عكس ترتيب عناصر المصفوفة، إذ نحتاج معظم الأحيان لترتيب عناصر غير مرتبة، ويمكن لذلك استخدام التابع sort لترتيب العناصر ضمن المصفوفة بأي طريقة نريدها، فإذا كانت العناصر ضمن المصفوفة قيم بسيطة مثل السلاسل النصية أو الأرقام، فسيرتب التابع sort تلك العناصر مباشرةً: sharks = ["Tiger", "Great White", "Hammerhead", "Angel"] sorted_sharks = sharks.sort print sorted_sharks ويعطي الخرج التالي: ["Angel", "Great White", "Hammerhead", "Tiger"] لترتيب البيانات بطريقة مختلفة يجب أن نخبر التابع sort بطريقة فعل ذلك، إذ يمكن تمرير كتلة برمجية للتابع sort الذي سيمرِّر لها عناصر المصفوفة لمقارنتها ويمكن ذلك باستخدام معامل المقارنة <=>، إليك مثالًا عن ذلك: 1 <=> 2 # -1 2 <=> 2 # 0 2 <=> 1 # 1 يقبل التابع sort في لغة روبي كتلةً برمجيةً يجب أن تعيد إحدى القيم 1- أو 0 أو 1 للتعبير عما إذا كان العنصر الأول يسبق أو يساوي أو يلي العنصر الثاني بالترتيب، وبناءً على تلك المقارنة تُرتب عناصر المصفوفة، وفي ما يلي مقارنة لقيم عناصر المصفوفة وترتيبها تصاعديًا: sharks = ["Tiger", "Great White", "Hammerhead", "Angel"] sorted_sharks = sharks.sort{|a,b| a <=> b } print sorted_sharks يُمثل المتغيران a و b عنصرين من المصفوفة يُقارن بينهما حاليًا، ونتيجة ترتيب المصفوفة هي: ["Angel", "Great White", "Hammerhead", "Tiger"] يمكن عكس ترتيب العناصر ضمن عبارة المقارنة بينهما لترتيب العناصر بترتيب عكسي على النحو التالي: sharks = ["Tiger", "Great White", "Hammerhead", "Angel"] sorted_sharks = sharks.sort{|a,b| b <=> a } print sorted_sharks ليكون الخرج: ["Tiger", "Hammerhead", "Great White", "Angel"] كما لاحظنا، يمكن باستخدام التابع sort ترتيب المصفوفات التي تحتوي على أنواع بسيطة من البيانات، مثل الأعداد الصحيحة، أو العشرية، أو السلاسل النصية، ولكن عندما تحتوي المصفوفة على كائنات أكثر تعقيدًا، سيكون عليك فعل المزيد. يوضح المثال التالي مصفوفة من قيم من نوع hash، وكل hash يمثّل سمك قرش shark: sharks = [ {name: "Hammerhead"}, {name: "Great white"}, {name: "Angel"} ] سيفشل ترتيبها مباشرةً باستخدام sort: sharks.sort وعند استدعائه على تلك المصفوفة تظهر الرسالة التالية: ArgumentError: comparison of Hash with Hash failed ولمقارنة تلك القيم يجب أن نخبر التابع sort بطريقة المقارنة بينها. لنرتب تلك الكائنات أبجديًا بحسب خاصية الاسمname: ضمنها على النحو التالي: sorted_sharks.sort{|a, b| a[:name] <=> b[:name]} print sorted_sharks ليكون الخرج: [{:name=>"Angel"}, {:name=>"Great white"}, {:name=>"Hammerhead"}] يمكن عند ترتيب مصفوفة من الكائنات استخدام التابع sort_by بدلًا من sort، الذي يستخدم خوارزمية أكثر كفاءة في الترتيب، ويقبل التابع sort_by كتلة برمجية يُمرر إليها وسيط واحد فقط وهو العنصر الحالي في المصفوفة: sharks = [ {name: "Hammerhead"}, {name: "Great white"}, {name: "Angel"} ] sorted_sharks = sharks.sort_by{|shark| shark[:name] } print sorted_sharks يكون الخرج هنا: [{:name=>"Angel"}, {:name=>"Great white"}, {:name=>"Hammerhead"}] يُطبق التابع sort_by خوارزمية ترتيب تدعى تحويل شوارتزيان Schwartzian transform، التي تُستخدم لمقارنة الكائنات بناءً على قيمة محددة منها، وهي خوارزمية أكثر كفاءة من خوارزمية الترتيب ضمن التابع sort؛ إذ يعيد كلًا من التابعين sort و sort_by مصفوفات جديدة دون تغيير قيمة المصفوفة الأصلية، وللتعديل على قيمة المصفوفة الأصلية نستخدم التابعين المقابلين لهما!sort و !sort_by، وقد نحتاج أحيانًا لحذف العناصر المكررة ضمن المصفوفة، وهذا ما سنتعرف عليه في الفقرة التالية. إزالة العناصر المكررة من المصفوفة قد تحتوي المصفوفات على بعض العناصر المكررة ضمنها، ولإزالة ذلك التكرار يمكن المرور على المصفوفة وإزالة التكرار منها يدويًا، أو يمكن استخدام التابع uniq، الذي يعيد مصفوفةً جديدةً تحتوي قيم المصفوفة نفسها ولكن دون التكرار: [1,2,3,4,1,5,3].uniq # [1,2,3,4,5] سنحاول في المثال التالي دمج مجموعتين من البيانات وسنعالج مشكلة تكرار بعض العناصر في المصفوفة الناتجة: sharks = ["Tiger", "Great White"] new_sharks = ["Tiger", "Hammerhead"] يمكن الدمج بينها باستخدام معامل الجمع + لنحصل على عنصر مكرر في المصفوفة الناتجة: sharks + new_sharks # ["Tiger", "Great White", "Tiger", "Hammerhead"] يمكن استخدام التابع uniq لإزالة التكرار في المصفوفة الناتجة، ولكن بدلًا من ذلك يمكن تجنب ذلك التكرار من الأساس باستخدام معامل الأنبوب | الذي يدمج المصفوفتين دون تكرار العناصر المشتركة بينهما بدلًا من معامل الجمع + وذلك على النحو التالي: sharks | new_sharks # ["Tiger", "Great White", "Hammerhead"] يمكن في روبي طرح المصفوفات من بعضها باستخدام معامل الطرح - للحصول على القيم غير المكررة فقط بين كلا المصفوفتين كما يلي: sharks = ["Tiger", "Great White"] new_sharks = ["Tiger", "Hammerhead"] sharks - new_sharks # ["Great White"] سنتعرف في الفقرة التالية على طرق التعديل على عناصر المصفوفة. تعديل عناصر المصفوفة يمكن استخدام التابع map أو التسمية البديلة له collect لتحويل محتويات المصفوفة بتطبيق عملية ما على كل عنصر في المصفوفة، فمثلًا يمكن تنفيذ عمليات حسابية على كل عنصر في المصفوفة وإنشاء مصفوفة جديدة تحتوي على قيمة تلك العملية الحسابية لكل عنصر منها: numbers = [2,4,6,8] # square each number squared_numbers = numbers.map {|number| number * number} print squared_numbers المتغير squared_numbers هو مصفوفة تحتوي على قيمة مربع كل عدد من المصفوفة الأصلية: [4, 16, 36, 64] يُستخدم التابع map غالبًا في تطبيقات الويب لتحويل عناصر من المصفوفة إلى عناصر HTML لعرضها ضمن قائمة منسدلة في الصفحة على النحو التالي: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] options = sharks.map {|shark| "<option>#{shark}</option>"} print options تحتوي المصفوفة الجديدة options على كل عنصر من المصفوفة الأصلية محاطًا بالوسم <option></option>: ["<option>Hammerhead</option>", "<option>Great White</option>", "<option>Tiger</option>", "<option>Whale</option>"] يعيد التابع map مصفوفةً بالقيم الجديدة دون التعديل على المصفوفة الأصلية، ويمكن باستخدام التابع !map تعديل قيمة المصفوفة الأصلية، ويمكن استخدام التسمية البديلة للتابع collect بنفس الطريقة، ويُفضّل اعتماد أحد هذين التابعين لتوحيد الاستخدام ضمن الشيفرة البرمجية، وبما أن التابع map يعيد مصفوفةً جديدة فيمكن تحويل أو تعديل عناصر تلك المصفوفة الجديدة مجددًا أو تحويلها مثلًا إلى سلسلة نصية، وسنتعرف على ذلك في الفقرة التالية. تحويل المصفوفة إلى سلسلة نصية تحتوي جميع الكائنات في لغة روبي على التابع to_s والذي يحوّل أي كائن إلى سلسلة نصية، وهذا ما يستخدمه التابع print داخليًا لطباعة الكائنات المٌمررة له على الشاشة. لنختبر ذلك على المصفوفة التالية: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] ينتج عن استدعاء التابع to_s على تلك المصفوفة السلسلة النصية التالية: "[\"Hammerhead\", \"Great White\", \"Tiger\", \"Whale\"]" قد تفيدنا تلك العملية في معاينة قيم المتغيرات أثناء تطوير البرامج. يوجد أيضًا التابع join، الذي يحوّل المصفوفة إلى سلسلة نصية بطريقة أخرى عبر دمج تلك العناصر بجانب بعضها بعضًا، ويقبل وسيطًا هو سلسلة نصية ستفصل بين تلك العناصر مثل المسافة الفارغة. لنختبر ذلك بتحويل المصفوفة السابقة إلى سلسلة نصية على النحو التالي: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] result = sharks.join(" ") print result لتكون النتيجة: Hammerhead Great White Tiger Whale يمكن بدلًا من المسافة الفارغة فصل القيم بفاصلة ومسافة بين العناصر بتمريرها للتابع كما يلي: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] result = sharks.join(", ") print result ويكون الخرج في هذه الحالة: Hammerhead, Great White, Tiger, Whale وإذا لم نمرر أي وسيط للتابع join، سيعيد سلسلةً نصيةً تحتوي على العناصر الموجودة في المصفوفة دون فواصل بينها: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] result = sharks.join print result وتكون النتيجة على النحو التالي: HammerheadGreat WhiteTigerWhale يمكن استخدام التابع join مع التابع map لتحويل مصفوفة من البيانات إلى نتيجة يمكن عرضها على الشاشة، إذ يحوّل التابع map كل عنصر من المصفوفة إلى الشكل الجديد، ثم يدمج التابع join تلك القيم في سلسلة نصية يمكن طباعتها على الشاشة، إذ يمكننا مثلًا تحويل العناصر إلى عناصر HTML كما فعلنا سابقًا ثم دمجها باستخدام التابع join في سلسلة نصية يفصل بينها أسطر جديدة: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] options = sharks.map {|shark| "<option>#{shark}</option>"} output = options.join("\n") print output ليعطي الخرج التالي: <option>Hammerhead</option> <option>Great White</option> <option>Tiger</option> <option>Whale</option> أحيانًا نحتاج لحساب قيمة إجمالية من عناصر المصفوفة أو تنفيذ عملية ما عليها ينتج منها قيمة واحدة، وسنتعرف على طريقة ذلك في الفقرة التالية. تقليص المصفوفة إلى قيمة واحدة يمكن حساب قيمة معينة من عناصر المصفوفة بالمرور على كل عنصر منها باستخدام التابع each ودمجه في النتيجة النهائية، مثل حساب المجموع الكلي للأرقام ضمن المصفوفة على النحو التالي: result = 0 [1, 2, 3].each {|num| result += num} print result سيكون الخرج: 6 يمكننا بدلًا من ذلك استخدام التابع reduce، الذي يُنفذ عمليةً معينة على كل عنصر من عناصر المصفوفة مع تمرير قيمة الدمج الحالية مع العنصر الحالي إلى الكتلة البرمجية المٌمررة له، إذ يقبل التابع reduce وسيطًا وهو القيمة الابتدائية للنتيجة ويستخدم الكتلة البرمجة المُمررة له والتي سيُمرر لها متغيرين هما قيمة الدمج الحالية والعنصر الحالي، ويمكن داخل الكتلة البرمجية تحديد طريقة إضافة العنصر الحالي إلى النتيجة النهائية، فمثلًا لجمع عناصر المصفوفة يمكن تمرير القيمة 0 مثل قيمة ابتدائية للنتيجة ثم إضافة قيمة كل عنصر من المصفوفة إلى النتيجة المُمررة داخل الكتلة البرمجية على النحو التالي: output = [1,2,3].reduce(0) {|result, current| result += current } print output لتكون النتيجة في الخرج: 6 وفي حال كانت النتيجة الابتدائية هي صفر 0، يمكننا اختصار تمريرها مثل وسيط للتابع وتمرير الكتلة البرمجية له فقط، إذ ستكون القيمة الابتدائية هي قيمة أول عنصر من المصفوفة: output = [1,2,3].reduce {|result, current| result += current } print output ويكون الخرج: 6 يمكن تحديد تابع ثنائي binary أو تابع عادي على كائن واحد يقبل كائنًا آخر مثل وسيط له ليٌستدعى على كل عنصر من عناصر المصفوفة، ويستخدم التابع reduce نتيجة ذلك الاستدعاء لإنشاء قيمة واحدة تدل على النتيجة النهائية، وعند جمع عددين مثلًا 2 + 2 في روبي، يٌفهم ذلك على أنه استدعاء لتابع الجمع + على كائن العدد 2 كما يلي: 2.+(2) # 4 يمكن استخدام الصيغة 2 + 2 في روبي لتسهيل القراءة لتلك العبارة البرمجية، وينتج عنها داخليًا في اللغة استدعاء لتابع الجمع + على العدد 2، وبما أن التابع reduce يسمح بتحديد تابع ثنائي لاستدعائه على كل عنصر من عناصر المصفوفة مع النتيجة، فيمكن تمرير اسمه على شكل رمز، مثل تمرير الرمز +: للتابع reduce مثلًا لاستدعاء تابع الجمع على كل عنصر لجمع عناصر المصفوفة: output = [1, 2, 3].reduce(:+) print output لتكون النتيجة في الخرج: 6 يمكن استخدام التابع reduce لتنفيذ العديد من العمليات على عناصر المصفوفة، إذ يمكن استخدامه لتحويل تلك القيم، كما يمكن استخدامه لتقليص قيم المصفوفة للحصول على قيمة مفردة، ولكن لا توجد قاعدة تنص على أن القيمة المفردة ليست بمصفوفة جديدة. إذا كان لدينا قائمة من القيم التي نريد تحويلها إلى أعداد صحيحة، ولكن نريد فقط اختيار القيم التي يمكن تحويلها إلى أعداد صحيحة، فيمكن استخدام التابع reject لإزالة القيم غير العددية، ثم استخدام التابع map لتحويل القيم المتبقية إلى أعداد صحيحة، أو يمكن فعل كل ذلك في خطوة واحدة باستخدام التابع reduce باستخدام مصفوفة فارغة مثل قيمة ابتدائية ثم نحول القيمة الحالية إلى عدد صحيح باستخدام التابع Integer في الكتلة البرمجية المُمررة، وإذا كانت القيمة غير قابلة للتحويل إلى عدد صحيح سيرمي التابع Integer استثناء يمكننا التقاطه وتبديل القيمة الحالية بالقيمة nil، ثم إضافة القيمة الحالية إلى مصفوفة النتيجة فقط إذا لم تكن nil على النحو التالي: values = ["1", "2", "a", "3"] integers = values.reduce([]) do |array, current| val = Integer(current) rescue nil array.push(val) unless val.nil? array end print integers سيكون الخرج: [1,2,3] كما لاحظنا، يُستخدم التابع reduce في حال كانت النتيجة النهائية من المصفوفة قيمة مفردة أو مصفوفة جديدة بطول مختلف عن المصفوفة الأصلية. الخاتمة تعرفنا في هذا المقال على العديد من الطرق للتعامل مع المصفوفات، إذ تعلمنا كيفية الوصول إلى عناصرها والبحث واستخراج بعض القيم منها وترتيب العناصر وتحويل البيانات ضمنها وإنشاء مصفوفات وسلاسل نصية وقيمة مجموع كلي جديدة. تفيد كل تلك المفاهيم في حل العديد من المشاكل البرمجية باستخدام لغة روبي وهي من أهم المهارات التي يجب على المبرمج اكتسابها. لمزيد من التفصيل، ارجع إلى صفحة النوع Array في موسوعة حسوب. ترجمة -وبتصرف- للمقال How To Use Array Methods in Ruby لصاحبه Brian Hogan. اقرأ أيضًا المقال السابق: التعامل مع المصفوفات في لغة روبي مقال السلاسل النصية في لغة روبي دليلك الشامل إلى أنواع البيانات
  3. المصفوفة array هي شكل من أشكال البيانات التي توفرها معظم لغات البرمجة والتي تسمح بتخزين عدة قيم تدعى عناصر معًا ضمن متغير واحد، ويمكن لهذه العناصر أن تكون من أنواع مختلفة من البيانات، مثل الأرقام والسلاسل النصية وغيرها من كائنات روبي. سنتعرف في هذا المقال على طرق إنشاء المصفوفات والوصول إلى القيم التي تحتويها، وإضافة وتعديل وحذف العناصر من المصفوفة، وطريقة المرور على عناصر المصفوفة، إذ تُعد المصفوفة في روبي كائنات مع توابعها الممكن استدعاؤها والاستفادة منها في التعامل مع عناصر المصفوفة. إنشاء مصفوفة في حال كان لدينا عدة قيم نحتاج التعامل معها ضمن البرنامج يمكننا تخزين كل منها في متغير خاص على النحو التالي: shark1 = "Hammerhead" shark2 = "Great White" shark3 = "Tiger" ولكن سنحتاج بتلك الطريقة لاختيار اسم متغير لكل قيمة منها، وفي حال كانت القيم كثيرة سيصبح الأمر صعبًا، وإذا أردنا إضافة قيمة جديدة إليها يجب تعريف متغير جديد وتذكُّر اسمه لاحقًا. هنا تأتي المصفوفات لحل تلك المشكلة عبر تخزين كل تلك القيم ضمن متغير واحد فقط. لإنشاء مصفوفة في روبي يمكن كتابة قيم العناصر ضمن أقواس معقوفة [] والفصل بينها بفواصل , على النحو التالي: sharks = ["Hammerhead", "Great White", "Tiger"] بدلًا من إنشاء ثلاثة متغيرات منفصلة أصبح لدينا الآن متغير واحد يحتوي على جميع القيم، ولإضافة قيمة جديدة للمصفوفة يمكن إضافتها مباشرةً دون الحاجة لإنشاء متغير جديد. يمكن طباعة كامل المصفوفة باستخدام التابع print، الذي سيعرض محتويات المصفوفة كما يلي: print sharks ليكون الخرج على النحو التالي: ["Hammerhead", "Great White", "Tiger"] توفر لغة روبي طريقةً مختصرةً لإنشاء مصفوفة يكون فيها كل مُدخل هو كلمة واحدة، وذلك بكتابة الكلمات بين القوسين في الصيغة التالية {}w% على النحو التالي: days = %w{Monday Tuesday Wednesday Thursday Friday Saturday Sunday} وسينتج عنها مصفوفة من الكلمات كما لو أننا عرفناها يدويًا ضمن أقواس معقوفة على النحو التالي: days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] ونلاحظ عدم الحاجة لاستخدام علامات الاقتباس لتعريف تلك الكلمات ضمن الصيغة {}w%، ولسنا مضطرين لتخزين عناصر من نفس النوع ضمن المصفوفة، ففي روبي يمكن للمصفوفات أن تحتوي على أي نوع من القيم بما في ذلك مصفوفات أخرى، وفيما يلي مثال على مصفوفة تحتوي على سلسلة نصية والقيمة nil وعدد صحيح ومصفوفة من السلاسل النصية: record = [ "Sammy", null, 7, [ "another", "array", ] ] سنتعرف في الفقرة التالية على كيفية الوصول إلى البيانات المخزنة ضمن المصفوفات. الوصول لعناصر المصفوفة للوصول إلى عنصر محدد ضمن المصفوفة يمكننا الإشارة إلى رقم الفهرس لذلك العنصر، أي ترتيب موقعه ضمن المصفوفة، إذ تبدأ الفهارس في روبي ومعظم لغات البرمجة الأخرى من الرقم صفر، فمثلًا للوصول إلى العنصر الأول من المصفوفة يمكننا تمرير رقم الفهرس له بعد اسم المتغير وبين الأقواس المعقوفة: sharks = ["Hammerhead", "Great White", "Tiger"] تحتوي المصفوفة sharks على ثلاثة عناصر، ورقم الفهرس لكل عنصر منها على النحو التالي: 2 1 0 Tiger Great White Hammerhead العنصر الأول في المصفوفة وهو Hammerhead له الفهرس رقم 0، أما العنصر الأخير في المصفوفة وهو Tiger له الفهرس رقم 2، إذ وعلى عكس طريقة العد التقليدية التي تبدأ بالرقم 1، نلاحظ أن الفهارس تبدأ من الصفر، لذا يجب الاعتياد على ذلك عند التعامل مع المصفوفات لتجنب الأخطاء. يمكن معرفة عدد العناصر الموجودة في المصفوفة باستخدام التابع length على النحو التالي: sharks.length ليكون الخرج على النحو التالي: 3 على الرغم من أن فهارس المصفوفة sharks تبدأ من 0 وتنتهي بالفهرس 2، إلا أن تابع طول المصفوفة length يعيد عدد العناصر الموجودة في المصفوفة والذي يساوي 3، ولا علاقة له برقم الفهرس للعناصر. ملاحظة: يمكنك التفكير في الفهرس على أنه إزاحة offset، أي عدد الأماكن من بداية المصفوفة، إذ يكون العنصر الأول في المقدمة وبالتالي بدون إزاحة، أي سيكون الفهرس 0، أما العنصر الثاني فهو على بُعد عنصر واحد من بداية المصفوفة، لذلك ستكون إزاحته بمقدار 1 وقيمة الفهرس 1. لمعرفة رقم الفهرس لعنصر محدد ضمن المصفوفة مثل العنصرTiger يمكن استخدام التابع ()index على النحو التالي: print sharks.index("Tiger") ليعطي الخرج التالي: 2 يعيد هذا التابع رقم الفهرس لأول عنصر من المصفوفة يحتوي على النص المحدد، وإذا لم يُعثر على عنصر مطابق لتلك القيمة فسيعيد التابع القيمة nil: print sharks.index("Whale") سيكون هنا الخرج: nil للحصول على آخر عنصر من المصفوفة يمكن استخدام رقم الفهرس السالب 1-: print sharks[-1] وسيكون الخرج كما يلي: "Tiger" ويوجد أيضًا التابعين first و last في روبي للحصول على أول وآخر عنصر من المصفوفة دون الحاجة إلى استخدام رقم الفهرس لها: puts sharks.first puts sharks.last ويكون الخرج: "Hammerhead" "Tiger" وعند محاولة الوصول إلى فهرس غير موجود: sharks[10] سينتج عن ذلك القيمة nil: nil يمكن أن تحتوي المصفوفات على مصفوفات أخرى ضمنها لينتج من ذلك مصفوفات متداخلة nested arrays يمكن الاستفادة من هذا الشكل من البيانات لتمثيل البيانات ثنائية الأبعاد في البرنامج، ويمكنك الاطلاع على مزيدٍ من المعلومات عن المصفوفات وأنواعها من خلال المقال المصفوفات Arrays في روبي، وفيما يلي مثال على مصفوفة متداخلة: nested_array = [ [ "salmon", "halibut", ], [ "coral", "reef", ] ] للوصول إلى العناصر الموجودة ضمن مصفوفة متداخلة يجب إضافة رقم فهرس إضافي يتوافق مع المصفوفة الداخلية، فمثلًا يمكن الوصول إلى القيمة coral من المصفوفة السابقة كما يلي: print nested_array[1][0]; ليكون الخرج على النحو التالي: coral نستخرج في هذا المثال العنصر الثاني أولًا من المصفوفة عبر رقم الفهرس 1 من المتغير nested_array، وهو عنصر المصفوفة ["coral", "reef"]، ثم نستخرج العنصر الأول من هذه المصفوفة عبر رقم الفهرس 0 لنحصل بذلك على القيمة المطلوبة "coral". سنتعرف في الفقرة التالية على طريقة إضافة عناصر إلى المصفوفة. إضافة عناصر إلى المصفوفات لنعود إلى المصفوفة السابقة sharks، التي تحتوي على ثلاثة عناصر تبدأ من رقم الفهرس 0 إلى 2: sharks = ["Hammerhead", "Great White", "Tiger"] لإضافة عنصر جديد إلى تلك المصفوفة، يمكن تعيين قيمة للفهرس الذي يلي آخر عنصر منها والذي في هذه الحالة هو 3 كما يلي: sharks[3] = "Whale"; print sharks ليكون الخرج على النحو التالي: ["Hammerhead", "Great White", "Tiger", "Whale"] قد يؤدي استخدام هذه الطريقة إلى حدوث أخطاء، فإذا أضفنا عنصرًا إلى رقم فهرس ما أكبر من ذلك فسيؤدي ذلك لإضافة العنصر nil داخل المصفوفة على النحو التالي: sharks[5] = "Sand"; print sharks; ويكون الخرج في هذه الحالة: ["Hammerhead", "Great White", "Tiger", "Whale", nil, "Sand"] وعند محاولة الوصول إلى قيمة ذلك العنصر الزائد سنحصل على القيمة nil: sharks[4] سيكون الخرج: nil يمكن استخدام التابع push لتجنب هذه الأخطاء، إذ يضيف هذا التابع عنصرًا إلى نهاية المصفوفة دون مشاكل: sharks.push("Thresher") print sharks وعندها سيكون الخرج: ["Hammerhead", "Great White", "Tiger", "Whale", nil, "Whale", "Thresher"] يمكن أيضًا استخدام الصيغة >> بدلًا من التابع push لإضافة عنصر إلى نهاية المصفوفة كما يلي: sharks << "Bullhead" ويكون الخرج: ["Hammerhead", "Great White", "Tiger", "Whale", nil, "Whale", "Thresher", "Bullhead"] نستخدم التابع ()unshift لإضافة عنصر إلى بداية المصفوفة كما يلي: sharks.unshift("Angel") print sharks ليعطي الخرج التالي: ["Angel", "Hammerhead", "Great White", "Tiger", "Whale", nil, "Whale", "Thresher", "Bullhead"] سنتعرف في الفقرة التالية على طريقة إزالة عناصر من المصفوفة. إزالة العناصر من المصفوفات يمكن استخدام التابع delete أو delete_at لإزالة عنصر محدد من المصفوفة. لنختبر ذلك بإزالة العنصر الفارغ داخلها والذي أنشأناه عن طريق الخطأ، ونبدأ بالعثور على موضعه في المصفوفة باستخدام التابع index على النحو التالي: print sharks.index(nil) والذي يعطينا الخرج التالي: 4 ثم نستخدم التابع delete_at لإزالة ذلك صاحب الفهرس رقم 4 ونطبع المصفوفة لنتأكد: sharks.delete_at(4) print sharks سيكون الخرج على النحو التالي: ["Angel", "Hammerhead", "Great White", "Tiger", "Whale", "Thresher", "Bullhead"] يزيل التابع delete العناصر التي تتطابق مع القيمة التي تُمرّر له. لنختبر استخدامه بإزالة العنصر Whale من المصفوفة السابقة كما يلي: sharks.delete("Whale") print sharks; ويكون الخرج في هذه الحالة: ["Angel", "Hammerhead", "Great White", "Tiger", "Thresher", "Bullhead"] يزيل التابع delete جميع القيم المطابقة للقيمة التي نمررها له، لذا إذا كانت المصفوفة تحتوي على عناصر مكررة فستُزال جميعها، وبالمقابل يتيح التابع pop إزالة آخر عنصر من المصفوفة: sharks.pop print sharks; ليكون الخرج كما يلي: ["Angel", "Hammerhead", "Great White", "Tiger", "Thresher"] نلاحظ إزالة العنصر Bullhead، وهو آخر عنصر في المصفوفة. لإزالة أول عنصر من المصفوفة يمكن استخدام التابع shift على النحو التالي: sharks.shift print sharks ليكون الخرج: ["Hammerhead", "Great White", "Tiger", "Thresher"] نلاحظ إزالة العنصر Angel من بداية المصفوفة، ويمكن استخدام التابعين pop و shift لإزالة العناصر من بداية ونهاية المصفوفة كما لاحظنا، ويفضل استخدام التابع pop عند الحاجة لأن حذف العنصر من نهاية المصفوفة لن يؤثر على رقم الفهرس لباقي العناصر. تعدل كلًا من التوابع delete_at و pop و shift على قيمة المصفوفة الأصلية وتعيد العنصر المحذوف: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] deleted_at_element = sharks.delete_at(1) popped_element = sharks.pop puts "Deleted_at element: #{deleted_at_element}" puts "Popped element: #{popped_element}" puts "Remaining array: #{sharks}" وسيكون الخرج: Deleted_at element: Great White Popped element: Whale Remaining array: ["Hammerhead", "Tiger"] بعد أن تعرفنا على طرق إزالة العناصر من المصفوفة، سنتعرف في الفقرة التالية على طريقة التعديل على قيمة عنصر من المصفوفة. تعديل عناصر موجودة في المصفوفات يمكن تحديث قيمة عنصر من المصفوفة عن طريق تعيين قيمة جديدة لفهرس ذلك العنصر باستخدام معامل الإسناد تمامًا كما نُعرف المتغيرات العادية. تحتوي المصفوفة التالية على العنصر "Hammerhead" في الفهرس رقم 0، لنحاول تعديل قيمة ذلك العنصر إلى القيمة "Angel": sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] sharks[0] = "Angel" print sharks; سيكون الخرج على النحو التالي: ["Angel", "Great White", "Tiger", "Whale"] يمكن التأكد من تعديل قيمة ذلك العنصر بالبحث عن القيمة الجديدة باستخدام التابع index لنلاحظ أن القيمة الجديدة موجودة في نفس المكان. سنتعرف في الفقرة التالية على طريقة المرور على عناصر المصفوفة. المرور على عناصر المصفوفة توفر لغة روبي العديد من الطرق للمرور على عناصر المصفوفة، ويختلف التابع المُستخدم بحسب الهدف الذي نريده. لنبدأ بالمرور على عناصر المصفوفة وطباعة قيمة كل منها وذلك باستخدام الصيغةfor..in على النحو التالي: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] for shark in sharks do puts shark end تعيّن روبي قيمة كل عنصر في المتغير المحلي shark، ويمكنك بعد ذلك طباعة قيمة ذلك العنصر باستخدام التابع puts. على الرغم من إمكانية استخدام الحلقة التكرارية for..in للمرور على عناصر المصفوفة، إلا أن المصفوفات في لغة روبي هي كائنات ويتوفر ضمنها التابع each، الذي يعمل بنفس طريقة الحلقة التكرارية for..in ولكن بصيغة مختلفة: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] sharks.each do |shark| puts shark end يستخدم التابع each صيغةً تتكرر كثيرًا في لغة روبي، إذ يأخذ التابع كتلة block مثل وسيط، ويُقصد بالكتلة هنا شيفرة برمجية ستنفذ لاحقًا في سياق التابع. ستُنفذ في مثالنا السابق العبارة البرمجية puts shark، أما الكلمة shark المحاطة بعلامات الأنبوب | هي المتغير المحلي الذي يمثل العنصر الحالي في المصفوفة، إذ تسنِد لغة روبي قيمة العنصر الحالي إلى هذا المتغير وتنفذ بعدها التعبير الموجود ضمن الكتلة، ويكرّر التابع each هذه العملية لكل عنصر من عناصر المصفوفة، ويكون الخرج على النحو التالي: Hammerhead Great White Tiger Whale يمكن استخدام الصيغة المختصرة ضمن الأقواس المعقوصة curly braces {} بدلًا من كلمتي do و end إذا كانت الكتلة مكونةً من سطر برمجي واحد فقط: ... sharks.each {|shark| puts shark } وسينتج عنها نفس الخرج السابق. يعمل التابع each_with_index بنفس طريقة التابع each، ولكنه يتيح الوصول إلى رقم الفهرس للعنصر الحالي في المصفوفة. لنختبر ذلك بطباعة رقم الفهرس والقيمة لكل عنصر من المصفوفة: sharks = ["Hammerhead", "Great White", "Tiger", "Whale"] sharks.each_with_index do |shark, index| puts "The index is #{index}" puts "The value is #{shark}" end تسند روبي قيمة كل عنصر في المصفوفة إلى المتغير shark، وتسند رقم الفهرس الحالي إلى المتغير index في كل مرة، ويمكن بعد ذلك الإشارة إلى هذين المتغيرين داخل الكتلة بحيث يمكن الوصول إلى قيمة العنصر الحالي ورقم فهرسه في المصفوفة. The index is 0 The value is Hammerhead The index is 1 The value is Great White The index is 2 The value is Tiger The index is 3 The value is Whale تعلمنا في هذه الفقرة عدة طرق للمرور على عناصر المصفوفة، وهي من أكثر المهمات التي نحتاجها عند التعامل مع المصفوفات. الخاتمة المصفوفات في روبي ومعظم لغات البرمجة من المفاهيم المهمة والقوية والتي يجب التعرف عليها وطرق التعامل معها. تعرّفنا في هذا المقال على المصفوفات وكل المهمات الأساسية للتعامل معها من إنشاء المصفوفات والوصول إلى عناصرها وإضافة وإزالة وتعديل العناصر ضمن المصفوفة، وتعرفنا على طريقتين للمرور على عناصر المصفوفة وعرض محتوياتها. لمزيد من التفصيل، ارجع إلى صفحة النوع Array في موسوعة حسوب. ترجمة -وبتصرف- للمقال How To Work with Arrays in Ruby لصاحبيه Brian Hogan و Tony Tran. اقرأ أيضًا المقال السابق: توابع السلاسل النصية في لغة روبي Ruby المصفوفات (Arrays) في روبي أنواع البيانات Data Types في لغة روبي
  4. تحتوي السلاسل النصية في لغة روبي على العديد من التوابع ضمنها والتي تسهل العديد من العمليات الشائعة على السلاسل النصية سنتعرف عليها في هذا المقال، والتي تفيد مثلًا في تحديد طول السلسلة النصية أو تقسيمها واستخراج أجزاء منها، أو إضافة وإزالة المسافات البيضاء whitespace والأحرف الأخرى منها، أو تغيير حالة الأحرف فيها، أو البحث عن نص معين فيها واستبداله بآخر، لينتج عن استخدام تلك التوابع مزايا قوية يمكن الاستفادة منها لحل العديد من المشاكل. تحديد طول سلسلة نصية تحتوي السلاسل النصية على التابع length والذي يُعيد عدد الأحرف في السلسلة النصية، فمثلًا يمكن الاستفادة من ذلك التابع لتحديد الحد الأدنى أو الأقصى لطول كلمة المرور في نظام ما والعديد من الاستخدامات، والمثال التالي يوضح طول سلسلة نصية مُخزنة ضمن متغير ويطبع النتيجة: open_source = "Sammy contributes to open source." print open_source.length ليكون الخرج على النحو التالي: 33 يجب التأكيد على أن كل المحارف ضمن السلسلة النصية بما في ذلك الحروف والأرقام والمسافات والرموز مأخوذة بالحسبان ضمن طول السلسلة النصية، ولمعرفة ما إذا كانت السلسلة النصية فارغة يمكن مقارنة طولها والتأكد بأنه يساوي الصفر 0، أو يمكن استخدام التابع المخصص لذلك وهو ?empty على النحو التالي: name = "" name.empty? # true name = "Sammy" name.empty? # false name = " " name.empty? # false سنتعرف في الفقرة التالية على طريقة الوصول إلى المحارف ضمن السلسلة النصية. الوصول إلى المحارف ضمن السلسلة النصية توفر لغة روبي التابع slice، الذي يفيد في استخراج جزء من السلسلة النصية. يُشار لكل محرف ضمن السلسلة النصية برقم الفهرس لها وهو رقم يبدأ ترتيبه من الصفر 0، تمامًا كما هو الحال بالنسبة للمصفوفات arrays في روبي، فمثلًا رقم الفهرس للمحارف في السلسلة النصية Sammy هو: 4 3 2 1 0 y m m a S يسمح التابع slice بالوصول إلى محرف واحد أو مجال من المحارف، فعند تمرير رقم صحيح واحد غليه سيُعيد المحرف الموجود في رقم الفهرس المحدد، وعند تمرير رقمين صحيحين مفصولين بفاصلة سيُعيد هذا التابع جميع المحارف بدءًا من رقم الفهرس الأول وحتى رقم الفهرس الثاني، ويمكن تمرير نطاق من الفهارس مثلًا من واحد إلى أربعة 4..1 لاستخراج الحروف الموجودة ضمن هذا النطاق: "Sammy".slice(0) # "s" "Sammy".slice(1,2) # "am" "Sammy".slice(1..4) # "ammy" ويمكن استخدام الصيغة [] والتي هي مرادف للتابع slice ليصبح شكل التعامل مع السلاسل النصية مشابه للمصفوفات: "Sammy"[0] # "s" "Sammy"[1,2] # "am" "Sammy"[1..4] # "ammy" يمكن الوصول إلى المحارف في نهاية السلسلة النصية باستخدام رقم فهرس سالب، فمثلًا الفهرس 1- يعيد المحرف الأخير من السلسلة النصية، والفهرس 2- يعيد المحرف ما قبل الأخير وهكذا، ويمكن تحويل سلسلة نصية إلى مصفوفة تحتوي على المحارف المكونة لها باستخدام التابع chars على النحو التالي: "sammy".chars # ["S", "a", "m", "m", "y"] يمكن استخدام هذه الطريقة للتعديل على محارف السلسلة النصية، وسنتعرف في الفقرة التالية على طريقة تغيير حالة الأحرف ضمن السلسلة النصية. تعديل حالة الأحرف يمكن استخدام التابع upcase لتحويل جميع الحروف الأجنبية في السلسلة النصية إلى أحرف كبيرة، والتابع downcase لتحويل جميع الحروف الأجنبية في السلسلة النصية إلى أحرف صغيرة، وتبقى الحروف بغير اللغة الإنجليزية كما هي دون تغيير. سنعدّل في المثال التالي السلسلة النصية "Sammy Shark" إلى حروف كبيرة: name = "Sammy Shark" print name.upcase SAMMY SHARK ليكون الخرج على النحو التالي: SAMMY SHARK ولنختبر تحويلها إلى أحرف صغيرة: print name.downcase سيكون الخرج هنا: sammy shark يسهّل استخدام التابعين upcase و downcase لمقارنة السلاسل النصية مع بعضها عن طريق توحيد حالة الأحرف قبل المقارنة، فمثلًا عند إدخال اسم مستخدم في برنامج ما من قِبل المستخدم بأحرف كبيرة، فيمكن تحويل القيمة المُدخلة إلى حروف صغيرة ثم مقارنتها القيم الموجودة ضمن النظام بأحرف صغيرة. توفر روبي أيضًا التابع capitalize، الذي يعيد نسخةً جديدةً من السلسلة النصية مع تحويل الحرف الأول منها إلى حرف كبير: "sammy".capitalize # "Sammy" وتوفر روبي أيضًا التابع swapcase والذي يعيد نسخةً جديدةً من السلسلة النصية مع تبديل حالة كل الأحرف فيها: text = "Sammy" print text.swapcase وسيكون الخرح في هذه الحالة: sAMMY تعيد التوابع downcase و upcase و capitalize و swapcase نسخةً جديدةً من السلسلة النصية وتترك السلسلة الأصلية دون تغيير، ويتوضح ذلك عند التعديل على قيمة سلسلة نصية مُخزنة ضمن متغير ما، فتبقى القيمة ضمن المتغير كما هي دومًا دون تغيير في حال لم نسنِد القيمة الجديدة مجددًا إلى المتغير: text = "sammy" text.capitalize print "Hello, #{text}!" ويكون الخرج على النحو التالي: Hello, sammy! على الرغم من استخدامنا للتابع capitalize على المتغير text في المثال السابق، وبما أننا لم نخزن القيمة المُعادة من capitalize مجددًا داخل المتغير text، فقيمة المتغير text لم تتغير، ولتغييرها يمكن إعادة كتابة الشيفرة السابقة بالشكل التالي لحل هذه المشكلة: text = "sammy" text = text.capitalize print "Hello, #{text}!" ويكون الخرح: Hello, Sammy! يمكن استخدام التوابع !downcase و !upcase و !capitalize و !swapcase (لاحظ انتهاء أسمائها بالمحرف !) للتعديل على قيمة السلسلة النصية الأصلية بدلًا من إنشاء سلسلة جديدة: text = "sammy" text = text.capitalize! print "Hello, #{text}!" ويجب الانتباه عند التعديل على قيمة السلسلة النصية الأصلية؛ فقد تعدّل قيمة سلسلة نصية في مكان ما ضمن البرنامج دون الانتباه إليه ما يؤدي لمشاكل، وسنتعرف في الفقرة التالية على طريقة إضافة وإزالة المسافات البيضاء من السلاسل النصية. إضافة وإزالة المسافات البيضاء الفارغة يمكن إضافة المسافات قبل أو بعد أو على كلا طرفي السلسلة النصية لتعديل تنسيقها قبل طباعتها مثلًا، وقد نحتاج أحيانًا لإزالة الأحرف غير الضرورية من بداية أو نهاية السلاسل النصية مثل المسافات الزائدة أو المحارف الخاصة. نبدأ بالتعرف على التابع center، الذي نمرر له طول السلسلة النصية الناتجة التي نريدها وسيضمن أنها بالطول المحدد، وذلك بإضافة مسافات بيضاء حول السلسلة نصية التي يُعالجها على النحو التالي: "Sammy",center(21) # " Sammy " ويمكننا استبدال المسافات البيضاء بنص معين نريد إضافته بتمريره لذلك التابع مثل وسيط ثانِ على النحو التالي: " [Sammy] ".center(21, "<>") # "<><><> [Sammy] <><><>" يضيف التابعان ljust و rjust مسافات بيضاء أو أحرف معينة إلى الجهة اليسرى أو اليمنى من السلسلة النصية ويعملان بالطريقة نفسها التي يعمل بها التابع center: "Sammy".ljust(20) # "Sammy " "Sammy".rjust(20) # " Sammy" "Sammy".rjust(20, "!") # "!!!!!!!!!!!!!!!Sammy" يمكن استخدام التابع rstrip لإزالة المسافات الزائدة في بداية السلسلة النصية، كما يمكن استخدام التابع lstrip لإزالة المسافات الزائدة في نهاية السلسلة النصية، أما التابع strip فيزيل المسافات الزائدة في كلا الجهتين (البداية والنهاية) من السلسلة النصية: " Sammy".rstrip # "Sammy" "Sammy ".lstrip # "Sammy" " Sammy ".strip # "Sammy" يمكن أيضًا استخدام التوابع !center و !ljust و !rjust و !lstrip و !rstrip و !strip لتعديل قيمة السلسلة النصية الأصلية، وفي بعض الأحيان قد نحتاج لإزالة الأحرف من نهاية السلسلة النصية لذلك يمكن استخدام التابع chop لإزالة المحرف الأخير من السلسلة النصية: "Sammy".chop # "Samm" قد نستفيد من ذلك لإزالة محرف السطر الجديد n\ مثلًا من نهاية سلسلة نصية ما: "This string has a newline\n".chop يترك التابع chop السلسلة النصية الأصلية دون تعديل ويعيد قيمة سلسلة نصية جديدة بدون المحرف الأخير، بينما يعدل التابع !chop السلسلة النصية الأصلية بدلًا من إنشاء سلسلة جديدة، ويمكن استخدام التابع chomp لإزالة عدة محارف من نهاية السلسلة النصية على النحو التالي: "Sammy".chomp("my") # "Sam" وفي حال لم نحدد السلسلة النصية التي نريد إزالتها من النهاية فسيزيل التابع chomp محرف السطر الجديد n\ فقط: "This string has a newline\n".chomp # "This string has a newline وفي حال لم تحتوي السلسلة النصية على محرف السطر الجديد n\ فسيعيد التابع chomp السلسلة النصية الأصلية كما هي دون تعديل: "Sammy".chomp # "Sammy" استخدام التابع chomp أسهل لإزالة محارف السطر الجديد n\ من نهاية السلسلة النصية من التابع chop والذي يزيل دائمًا الحرف الأخير مهما كان نوعه، كما توفر لغة روبي التابع !chomp، الذي يعدل قيمة السلسلة النصية الأصلية ويعيد السلسلة النصية المعدلة إذا أزال محارف من نهاية السلسلة، ولكن وعلى عكس التابع chomp فسيعيد التابع !chomp القيمة nil إذا لم يُعدل على السلسلة النصية: string = "Hello\n" string.chomp! # "Hello" string = "Hello" string.chomp! # nil سنتعرف في الفقرة التالية على طريقة البحث ضمن السلاسل النصية. البحث عن المحارف والنصوص نحتاج أحيانًا لتحديد ما إذا كانت السلسلة النصية تحتوي على نص معين أم لا، لهذا الغرض توفر روبي التابع ?include، الذي يتحقق مما إذا كانت السلسلة النصية تحتوي على سلسلة نصية أخرى، ويعيد القيمة المنطقية true إذا كانت السلسلة النصية تحتوي على السلسلة النصية الأخرى، أو القيمة false في حال لم تحتويها: "Sammy".include?("a") # true "Sammy".include?("b") # false يعيد التابع index رقم الفهرس لمكان محرف أو سلسلة نصية ما، أو يعيد القيمة nil في حال عدم العثور على المحرف أو السلسلة النصية الجزئية ضمنها: "Sammy".index("a") # 1 "Sammy".index("mm") # 2 "Sammy".index("Fish") # nil يبحث التابع index عن أول تواجد للمحرف أو السلسلة النصية المطلوبة فقط ويعيد رقم الفهرس له. لنوضح ذلك في المثال التالي على سلسلة نصية طويلة: text = "Sammy has a balloon" text.index("a") # 1 تحتوي السلسلة النصية "Sammy has a balloon" على أربعة حروف "a"، ولكن التابع index يعيد فقط موقع أول ظهور لذلك الحرف، ويجب أخذ ذلك بالحسبان عند البحث ضمن السلاسل النصية، ولتحديد كل ظهور للحرف "a" ضمن الجملة السابقة يمكن تحويل السلسلة النصية إلى مصفوفة من الأحرف المكونة لها ثم الاستعانة بتوابع المصفوفة للبحث بين تلك الحروف عن كل مكان لذلك الحرف وتحديد رقم الفهرس له مثلًا على النحو التالي: text = "Sammy has a balloon" indices = text.chars .each_with_index .select{|char, index| char == "a" } .map{|pair| pair.last} print indices [1, 7, 10, 13] ليكون الخرج على النحو التالي: [1, 7, 10, 13] يعيد التابع each_with_index مصفوفة ثنائية الأبعاد يحتوي كل عنصر منها على الحرف ومكانه ضمن السلسلة النصية، ونختار ضمن التابع select العناصر التي تحتوي على الحرفa، ثم نحول تلك العناصر باستخدام التابع map إلى مصفوفة تحتوي على رقم الفهرس لكل تواجد للحرف a، ويمكن التحقق مما إذا كانت السلسلة النصية تبدأ بحرف أو سلسلة نصية معينة باستخدام التابع ?start_with كما يلي: text = "Sammy has a balloon" text.start_with?("s") # true text.start_with?("Sammy has" # true يقبل التابع ?start_with سلسلةً نصيةً واحدةً أو أكثر مثل وسطاء له، ويعيد true إذا تطابق أي من تلك السلاسل النصية مع بداية السلسلة الأصلية: text = "Sammy has a balloon" text.start_with?("Sammy the Shark", "Sammy") # true لم يُعثر في هذا المثال على السلسلة النصية "Sammy the Shark"، ولكن عُثر على السلسلة النصية "Sammy"، لذا أرجع التابع القيمة true، وبالمقابل يمكن استخدام التابع ?end_with للتحقق مما إذا كانت السلسلة النصية تنتهي بسلسلة نصية معينة، إذ يعمل هذا التابع بنفس طريقة عمل التابع ?start_with: text = "Sammy has a balloon" text.end_with?("balloon") # true text.end_with?("boomerang") # false text.end_with?("boomerang", "balloon") # true بعد أن تعرفنا على طرق البحث ضمن النصوص، سنتعرف في الفقرة التالية على طريقة استبدال أجزاء معينة من السلسلة النصية. استبدال أجزاء من النص في السلاسل النصية يمكن البحث عن سلسلة نصية واستبدالها بأخرى باستخدام خاصية البحث والاستبدال المتوفرة عادةً في محررات النصوص التي نستخدمها، ويمكن تنفيذ هذه الميزة في لغة روبي باستخدام التوابع sub و gsub، إذ يبدل التابع sub جزءًا من النص بجزء آخر. سنغيّر في المثال التالي الجزء "has" إلى "had" في الجملة التالية: balloon = "Sammy has a balloon" print balloon.sub("has","had") ليعيد التابع قيمة النص بعد التبديل: Sammy had a balloon. يستبدل التابع sub أول ورود للنص المطابق بالنص الجديد فقط. لتوضيح ذلك سنستخدم الجملة التالية المعدّلة التي تحتوي على ورودين للكلمة "has": balloon = "Sammy has a balloon. The balloon has a ribbon" print balloon.sub("has","had") وسيكون الخرج على النحو التالي: Sammy had a balloon. The balloon has a ribbon نلاحظ تبديل أول ظهور فقط، ولتبديل جميع الأماكن التي ترد فيها السلسلة النصية يمكن استخدام التابع gsub الذي يبدل على مستوى النص بأكمله: balloon = "Sammy has a balloon. The balloon has a ribbon" print balloon.gsub("has","had") Sammy had a balloon. The balloon had a ribbon ويكون الخرج: Sammy had a balloon. The balloon had a ribbon تعيد التوابع sub و gsub سلسلةً نصيةً جديدةً دون تعديل السلسلة الأصلية، ويمكن توضيح ذلك بتغيير الكلمة "balloon" إلى "boomerang" في السلسلة النصية التالية: text = "Sammy has a balloon" text.gsub("ballooon", "boomerang") print text Sammy has a balloon التي تعطي الخرج التالي: Sammy has a balloon نلاحظ بقاء النص كما هو على الرغم من إمكانية الاستبدال، وذلك لأننا لم نخزن نتيجة التابع gsub في المتغير مجددًا، وللحصول على النتيجة التي نريدها يمكننا تعديل الشيفرة كما يلي: text = "Sammy has a balloon" text = text.sub("ballooon", "boomerang") print text أو يمكن استخدام التابع !sub بدلًا من التابع subوالذي يعدل على السلسلة الأصلية بدلًا من إعادة سلسلة جديدة. سنستخدم في المثال التالي التابع !sub لتغيير الجملة "red balloon" إلى "blue boomerang": text = "Sammy has a red balloon" text.sub!("red", "blue") text.sub!("balloon", "boomerang") print text ليكون الخرج على النحو التالي: Sammy has a balloon يمكن استخدام التابع !gsub لاستبدال كل ورود للنص المحدد والتعديل على قيمة السلسلة النصية الأصلية، ويمكن تمرير التعابير النمطية Regular Expressions -أو اختصارًا regex- للتوابع sub و gsub للبحث عن نمط معين، ففي المثال التالي سنبدل جميع الحروف الصوتية ضمن النص بالرمز @: "Sammy has a red balloon".gsub(/[aeiou]/, "@") وسيكون الخرج على النحو التالي: "S@mmy h@s @ r@d b@ll@@n" ويمكن تمرير جدول Hash بدلًا من سلسلة نصية ثابتة لتحديد كيفية استبدال كل جزء من النص الوارد بصورةٍ مختلفة، ففي المثال التالي سنبدّل جميع حروف "a" إلى المحرف "@" وجميع الحروف "o" إلى الرقم صفر: "Sammy has a red balloon".gsub(/[aeiou]/, {"a" => "@", "o" => "0"}) # "S@mmy h@s @ rd b@ll00n" نلاحظ أن ذلك يمنحنا إمكانية إجراء عمليات تبديل معقدة على النصوص والذي يفيدنا في حل بعض المشاكل المعقدة. الخاتمة تعرفنا في هذا المقال على العديد من التوابع التي تسمح لنا بالتعامل مع السلاسل النصية باستخدام توابع مبينة مسبقًا لنوع البيانات الخاص بالسلاسل النصية، ومنها ما كان يترك السلسلة الأصلية دون تعديل ومنها من يعدّل عليها. يعتمد اختيار التوابع التي سنستخدمها على احتياجاتنا، إذ تمنح لغة روبي المبرمجين المرونة لاختيار التوابع التي تفيدهم في العمل مع البيانات الخاصة بهم، وينصح باستخدام التوابع التي لا تعدل على القيمة الأصلية لأنها أسهل في تطوير البرامج وتجنب الأخطاء. لمزيد من التفصيل، ارجع إلى صفحة النوع String في موسوعة حسوب. ترجمة -وبتصرف- للمقال How To Work with String Methods in Ruby لصاحبه Brian Hogan. اقرأ أيضًا المقال السابق: السلاسل النصية في لغة روبي Ruby السلاسل والمتغيرات في روبي الدليل السريع إلى لغة البرمجة روبي
  5. السلسلة النصية string هي سلسلة من محرف واحد أو أكثر، والمحرف هو إمّا حرف أو رقم أو رمز، وقد ذكرنا في المقال السابق أن السلاسل النصية في لغة روبي تتمثل بكائن، وعلى عكس لغات البرمجة الأخرى تكون السلاسل النصية في روبي قابلةً للتعديل على قيمتها مباشرةً ضمن نفس المتغير، وهي من أكثر أنواع البيانات استخدامًا، إذ تسمح بعرض النصوص التي تفيد مثل طريقة تواصل نصية مع المستخدم، فمثلًا يتألف هذا المقال من سلاسل نصية يُظهرها متصفح الويب على الشاشة. سنتعرف في هذا المقال على طرق التعامل مع السلاسل النصية في لغة روبي بدءًا من طريقة إنشائها وعرضها على الشاشة وتخزينها في متغيرات ودمجها معًا، وسنتعرف أيضًا على طريقة التعامل مع المحارف الخاصة مثل الأسطر الجديدة والفواصل وعلامات الاقتباس المزدوجة double quotes. إنشاء وطباعة السلاسل النصية يمكن تعريف السلاسل النصية في لغة روبي بكتابة مجموعة من المحارف بين علامتي اقتباس مفردة ' أو علامتي اقتباس مزدوجة " على النحو التالي: 'This is a string in single quotes.' "This is a string in double quotes." يمكن استخدام إما علامتي اقتباس مفردة أو مزدوجة، وفي معظم الحالات لا يوجد فرق بينهما، بشرط استخدام نفس العلامة في بداية ونهاية السلسلة النصية؛ وميزة استخدام علامة الاقتباس المزدوجة أنها تسمح بتركيب السلاسل النصية وسنتعرف على تلك الميزة لاحقًا في هذا المقال. يمكن طباعة السلسلة النصية على الشاشة باستخدام التابع print على النحو التالي: print "Let's print out this string." يعرض التابعprint السلسلة النصية كما هي دون إجراء أي تعديل عليها. لنختبر ذلك عن طريق إنشاء ملف روبي جديد بالاسم "print.rb"، ونكتب داخله باستخدام محرر النصوص عدة أوامر طباعة للسلاسل النصية على النحو التالي: print 'This is the first string.' print 'This is the second string.' print 'This is the third string.' نحفظ الملف وننفذ البرنامج: $ ruby print.rb ليظهر الخرج التالي: This is the first string.This is the second string.This is the third string. نلاحظ طباعة كل السلاسل النصية على نفس السطر، ويمكن طباعة كل منها بسطر جديد عن طريق إضافة محرف السطر الجديد يدويًا لنهاية كل منها، أو استخدام التابع puts، الذي يضيف حرف السطر الجديد تلقائيًا في نهاية كل سلسلة نصية. لاختبار ذلك، نعدّل على البرنامج السابق ونبدّل التابع print بالتابع puts على النحو التالي: puts 'This is the first string.' puts 'This is the second string.' puts 'This is the third string.' عند تنفيذ البرنامج نلاحظ الخرج التالي: This is the first string. This is the second string. This is the third string. يطبع التابعputs السلسلة النصية المُمررة له بعد إضافة محرف السطر الجديد تلقائيًا في نهايتها. تخزين السلاسل النصية ضمن متغيرات تشير المتغيرات إلى مكان ما في ذاكرة الحاسوب نسند إليه اسمًا، وتفيد في تخزين البيانات لاسترجاعها لاحقًا، ولتخزين سلسلة نصية ضمن متغيرٍ ما، نعرف اسم المتغير ونسند قيمة السلسلة النصية إليه على النحو التالي: my_string = 'This is my string' بعد تعريف المتغير يمكن الإشارة إليه عن طريق اسمه لتمريره مثلًا إلى تابع ما كما يلي: print my_string لاختبار ذلك ننشئ الملف "string_variables.rb": $ nano string_variables.rb ونضيف التالي: my_name = "Sammy the Shark" my_age = "none of your business" puts my_name puts my_age يُعرّف هذا البرنامج المتغيرين my_name و my_age ويسند لكل منهما قيمة سلسلة نصية، ثم يستخدم التابع puts لطباعة كل سلسلة نصية منهما على سطر منفصل. نحفظ الملف من خلال الضغط على المفتاحين "CTRL + X" ثم على المفتاح "y" ثم ننفذ البرنامج على النحو التالي: $ ruby string_variables.rb ليظهر الخرج التالي: Sammy the Shark none of your business من خلال تعريف المتغيرات وإسناد قيم السلاسل النصية إليها يصبح من السهل التعامل معها وكذلك نتجنب تكرار كتابة نفس السلسلة النصية مرارًا وتكرارًا عند كل استخدام. سنتعرف في الفقرة التالية على طريقة دمج السلاسل النصية معًا لإنشاء سلاسل نصية جديدة. دمج السلاسل النصية يعني دمج السلاسل النصية concatenation دمج سلسلتين نصيتين أو أكثر لإنشاء سلسلة نصية جديدة، ويمكن لتنفيذ ذلك استخدام معامل الدمج الممثل بالرمز + والذي يستخدم أيضًا في عمليات الجمع في العمليات الحسابية، كما في المثال التالي: "sammy" + "shark" لينتج سلسلة نصية جديدة مكونة من دمج تلك السلسلتين: sammyshark لإضافة مسافة بين السلسلتين النصيتين، ينبغي عليك إضافة تلك المسافة ضمن إحدى السلسلتين على النحو التالي: "sammy " + "shark" ويمكن دمج السلاسل النصية مع تلك المُخزنة ضمن المتغيرات بنفس الطريقة: color = "Blue" print "My favorite color is " + color لينتج عن تلك العملية السلسلة النصية "My favorite color is blue"، ونلاحظ إضافة مسافة بنهاية السلسلة النصية الأولى لإضافة مسافة بين النص وقيمة المتغير في النتيجة، ويمكن دمج عدة سلاسل النصية معًا بنفس الطريقة. لنختبر ذلك بإنشاء الملف "concatenation.rb" ونضيف داخله التالي: my_name = "Sammy the Shark" my_age = "none of your business" puts "My name is " + my_name + " and my age is " + my_age + "." يُعرّف هذا البرنامج المتغيرين my_name و my_age، ويُسند لكل منهما قيمة سلسلة نصية كما فعلنا سابقًا، ولكن سنطبع هذه المرة سلسلةً نصيةً مكونةً من دمج عدة قيم مع بعضها، وعند تنفيذ البرنامج يظهر التالي: My name is Sammy the Shark and my age is none of your business. تفيد هذه الطريقة في إدراج قيم المتغيرات داخل السلسلة النصية الجديدة، وينتج عن دمج سلسلتين نصيتين أو أكثر سلسلةً نصيةً جديدةً يمكن استخدامها مثل أي سلسلة نصية أخرى، كأن نسند قيمتها مثلًا لمتغير جديد لاستخدامه لاحقًا: my_name = "Sammy the Shark" my_age = "none of your business" # assign concatenated string to variable output = "My name is " + my_name + " and my age is " + my_age + "." # Print the output. puts output استخدام متغير output إضافي في المثال السابق أمرٌ غير ضروري، إذ تفيد هذه الطريقة في البرامج الأكبر حجمًا، إذ قد تكون هناك حاجة لاستخدامه في أماكن متعددة من البرنامج، كما يُفضّل الفصل بين تنفيذ العمليات على البيانات مثل الدمج والعمليات الحسابية، وبين عملية الطباعة، لأن البرامج مع مرور الوقت ستكبر ولا بُد من تقليل التعقيد فيها، كما يجب التأكد من عدم استخدام معامل الدمج + بين نوعي بيانات مختلفين، فمثلًا لا يمكن دمج سلسلة نصية مع عدد صحيح. دعنا نرى ماذا سيحدث، وننشئ الملف الجديد "strings_and_integers.rb" الذي يحتوي على التالي: my_name = "Sammy the Shark" my_number = 27 print my_name + my_number عرفنا في هذا المثال، المتغير my_name، الذي يحتوي على السلسلة النصية "Sammy the Shark"، والمتغير my_number الذي يحتوي على العدد الصحيح 27، ومن الواضح أن العدد 27 ليس سلسلةً نصيةً لأنه ليس واقعًا بين علامتي اقتباس، وليس عددًا عشريًا أيضًا لأنه لا يحتوي على فاصلة عشرية، فهو من نوع عدد صحيح، وعند تنفيذ البرنامج على النحو التالي: $ ruby strings_and_ints.rb تظهر رسالة الخطأ التالية: strings_and_ints.rb:4:in `+': no implicit conversion of Integer into String (TypeError) from strings_and_ints.rb:4:in `<main>' تعني رسالة الخطأ "no implicit conversion of Integer into String" أنه يمكن دمج سلسلة نصية مع سلسلة نصية فقط، ولا يمكن دمج عدد صحيح مع سلسلة نصية مباشرةً. سيظهر عند تنفيذ البرنامج في إصدار روبي رقم Ruby 2.3 وما قبل رسالة الخطأ التالية بدلًا من ذلك: strings_and_ints.rb:4:in `+': no implicit conversion of Fixnum into String (TypeError) from strings_and_ints.rb:4:in `<main>' ملاحظة: في الإصدارات السابقة من روبي كنا نعبّر عن الأعداد الصحيحة باستخدام الكلمة المفتاحية Fixnum (اختصارًا للعبارة Fixed Number) وفي إصدار Ruby 2.4 استُبدل كل من Fixnum ونظيرتها Bignum بالكلمة Integer. يمكننا حل المشكلة بتعديل البرنامج السابق وإضافة علامتي اقتباس حول الرقم 27 ليصبح "27" لتعريفه على أنها سلسلة نصية بدلًا من عدد صحيح، أو يمكننا تحويل العدد إلى سلسلة نصية باستدعاء التابع to_s منه عند إنشاء السلسلة النصية كما يلي: my_name = "Sammy the Shark" my_number = 27 print my_name + my_number.to_s يحول التابع to_s. العدد الصحيح إلى سلسلة نصية، وتُعد تلك الطريقة أفضل، إذ يمكن الاحتفاظ بالعدد على أنه عدد صحيح داخل البرنامج كما هو، وتحويله إلى سلسلة نصية عند الحاجة فقط، أي أثناء طباعته مثلًا، وبذلك يمكن استخدامه على أنه عدد صحيح في أماكن أخرى من البرنامج، وعند تنفيذ البرنامج مرةً أخرى سنلاحظ طباعة السطر "Sammy the Shark27". تُعد عملية تحويل الأرقام إلى سلاسل نصية لدمجها معًا من العمليات التي نحتاجها بصورةٍ متكررة عند التعامل مع مختلف أنواع البيانات، مثل أرقام الهواتف والقيم النقدية وعناوين البريد وغيرها من البيانات التي نحتاج لعرضها على الشاشة ضمن سلسلة نصية. عملية الدمج مهمة جدًا، ولكن استخدامها قد يكون صعبًا أحيانًا، فإذا نسينا إضافة معامل الجمع + عن طريق الخطأ بين كل زوج من السلاسل النصية التي نحاول دمجها فسينتج خطأ في الصياغة عند تنفيذ البرنامج، ويجب تذكر تحويل الأعداد إلى سلاسل نصية قبل دمجها، لهذا السبب توفر روبي طريقةً أخرى لإدراج قيم المتغيرات داخل السلاسل النصية تدعى تضمين السلاسل string interpolation والتي تحل كلتا المشكلتين وسنتعرف عليها في الفقرة التالية. التضمين في السلاسل النصية ينتج عن دمج السلاسل النصية والمتغيرات معًا باستخدام معامل الدمج + عبارة برمجية صعبة القراءة والفهم، ومن هنا تأتي ميزة التضمين في السلاسل النصية، إذ تسمح بإدراج العبارات البرمجية داخل سلسلة نصية واحدة محاطة بعلامتي اقتباس مزدوجة حصرًا، فبدلًا من دمج القيم على النحو التالي: "My name is " + my_name + "!" يمكننا استخدام ميزة التضمين كما يلي: "My name is #{my_name}!" نلاحظ أنه وبدلًا من إنهاء السلسلة النصية واستخدام معامل الجمع + لدمجها بقيمة أخرى، نُضمّن قيمة المتغير مباشرةً داخل السلسلة النصية باستخدام الصيغة {}#، وفيها نخبر روبي بتقييم التعبير البرمجي داخلها ودمجه في ذلك المكان من السلسلة النصية. لنختبر ذلك بإنشاء ملف برنامج جديد بالاسم "interpolation.rb" ونضيف ما يلي: my_name = "Sammy the Shark" my_age = "none of your business" output = "My name is #{my_name} and my age is #{my_age}." puts output وهو نفس البرنامج الذي كتبناه سابقًا ولكن باستخدام التضمين لإنشاء النتيجة النهائية. يتيح التضمين ميزةً أخرى وهي تحويل القيم الرقمية إلى سلاسل نصية تلقائيًا قبل دمجها، ولاختبار ذلك نعود إلى الملف "strings_and_integers.rb" الذي كتبناه سابقًا ونغير السطر الأخير ليصبح على النحو التالي: my_name = "Sammy the Shark" my_number = 27 # use interpolation instead of concatenation print "My name is #{my_name} and my favorite number is #{my_number}." ستحوّل روبي المتغير my_number إلى سلسلة نصية تلقائيًا، ونلاحظ ذلك عند تشغيل البرنامج والذي سيطبع النتيجة التالية دون حدوث أخطاء: My name is Sammy the Shark and my favorite number is 27. نلاحظ قوة ميزة التضمين في السلاسل النصية فهي الطريقة المفضلة دومًا لدمج السلاسل النصية مع قيم المتغيرات الأخرى بسهولة في التعامل والقراءة. صياغة السلسلة النصية وقيمتها نلاحظ أن جميع السلاسل النصية التي أنشأناها محاطةٌ بعلامات الاقتباس ضمن الشيفرة البرمجية، ولكن الناتج النهائي عند الطباعة لا يتضمن علامات الاقتباس، ويوجد فرق بين الاشارة إلى السلاسل النصية في الشفرة البرمجية وما يُطبع، فالسلسلة النصية المكتوبة في الشيفرة البرمجية بما في ذلك علامات الاقتباس هي صياغة السلسلة النصية، بينما النتيجة التي تُعرض للمستخدم دون علامات الاقتباس بعد معالجة تلك القيمة هي قيمة تلك السلسلة. يمثل ما يلي صياغة لسلسلة نصية: "Sammy the Shark" وقيمة السلسلة النصية تلك هي العبارة Sammy the Shark، ويبرز الفرق بين صياغة السلسلة النصية وقيمتها عند استخدام المحارف الخاصة مثل علامات الاقتباس أو الفواصل ضمن السلسلة النصية، وسنتعرف على طريقة إدراجها في الفقرة التالية. إدراج علامات الاقتباس ضمن السلاسل النصية تُستخدم علامات الاقتباس المفردة والمزدوجة ضمن لغة روبي لتحديد بداية ونهاية السلسلة النصية، لذلك لا يمكن استخدامها ضمن قيمة السلسلة النصية نفسها، فإذا حاولنا مثلًا استخدام علامة اقتباس مفردة ضمن سلسلة نصية محاطة بعلامات اقتباس مفردة سيحدث خطأ: 'This isn't what I wanted.' إذ ستفهم لغة روبي علامة الاقتباس المفردة ضمن الكلمة isn't بأنها نهاية السلسلة النصية، وقبلها وما بعدها هو شيفرة روبي وليس تكملة للنص مما سينتج عنه خطأ، وتنطبق نفس الحالة على استخدام علامات الاقتباسات المزدوجة في سلسلة نصية محاطة بعلامات اقتباس مزدوجة كما هو الحال في المثال التالي: "Sammy says, "Hello!"" ففي هذا المثال تنتهي السلسلة النصية عند علامة الاقتباس المزدوجة الأولى قبل الكلمة Hello، وتبدأ شيفرة روبي اعتيادية بعدها مما يؤدي إلى حدوث خطأ. لتجنب هذه المشكلة لدينا عدة خيارات؛ إذ يمكن استخدام علامات الاقتباس المقابلة لعلامة الاقتباس التي نريد إدراجها ضمن النص، فمثلًا عند الحاجة إلى استخدام علامات الاقتباس المزدوجة ضمن السلسلة النصية، نُعرف السلسلة النصية باستخدام علامات اقتباس مفردة والعكس صحيح؛ أو يمكن استخدام محارف الهروب؛ أو استخدام صيغ مختلفة لإنشاء السلاسل النصية في روبي سنتعرف على كل من تلك الطرق على حدى في الفقرات التالية. الخيار الأول: استخدام علامات الاقتباس المقابلة أسهل طريقة لإدراج علامات الاقتباس ضمن السلاسل النصية هي استخدام علامات الاقتباس المقابلة للعلامة المُدرجة، فعندما تحتوي السلسلة النصية على علامات اقتباس مزدوجة، نستخدم العلامات المفردة لتعريف السلسلة النصية، وعندما تحتوي السلسلة النصية على علامات اقتباس مفردة نستخدم علامات الاقتباس المزدوجة لتعريف السلسلة النصية، فبدلًا من تعريف السلسلة النصية التالية بعلامات الاقتباس المفردة: 'This isn't what I wanted.' سنعرفها باستخدام علامات اقتباس مزدوجة: "This isn't what I wanted." وبدلًا من تعريف القيمة التالية باستخدام علامات اقتباس مزدوجة: "Sammy says, "Hello!"" سنستخدم علامات الاقتباس المفردة: 'Sammy says, "Hello!"' لا يمكن الاعتماد على هذا الحل دومًا، سوى عند استخدام نوع واحد من علامات الاقتباس ضمن السلسلة النصية، أما عند استخدام كلا النوعين كما هو واضح في المثال التالي: "Sammy says, "I'm a happy shark!"" في هذا المثال، تنتهي السلسلة النصية عند علامة الاقتباس المزدوجة الأخيرة قبل I'm، ومن ثم تبدأ روبي في قراءة الكلمة I'm والتي تبدأ فيها بسلسلة نصية جديدة بقيمة ""!m a happy shark، ولكن هذه السلسلة النصية الجديدة لا تحتوي على علامة اقتباس مفردة تُنهيها، وعند محاولة استخدام علامات الاقتباس المفردة لتعريف السلسلة النصية تُضمّن علامة اقتباس مفردة داخل النص مما يؤدي إلى نفس المشكلة: 'Sammy says, "I'm a happy shark!"' تنتهي السلسلة النصية هذه المرة عند علامة الاقتباس المفردة بعد كلمة I'm، واللجوء لهذا الخيار دومًا يجعل السلاسل النصية ضمن البرنامج الواحد غير متناسقة، فتارةً يجب استخدام العلامات المفردة وتارةً أخرى المزدوجة. لحل تلك المشكلة يمكننا استخدام طريقة محارف الهروب Escaping characters التي سنتعرف عليها في الفقرة التالية. الخيار الثاني: استخدام محارف الهروب في السلاسل النصية يمكن استخدام محارف الهروب ضمن السلاسل النصية وذلك بوضع خط مائل عكسي \ قبلها، لإخبار روبي بأن المحرف التالي لها على هو جزء من السلسلة النصية نفسها. لتوضيح فائدة تلك الطريقة سنحاول معالجة النص التالي الذي يحتوي على علامات اقتباس مزدوجة ومفردة داخله: "Sammy says, "I'm a happy shark!"" ننشئ ملف جديد بالاسم "quoting.rb" بداخله التالي: print "Sammy says, "I'm a happy shark!"" ننفذ البرنامج: $ ruby quoting.rb ونلاحظ ظهور خطأ بسبب وجود علامات الاقتباس المزدوجة داخل السلسلة النصية: quoting.rb:1: syntax error, unexpected tCONSTANT, expecting end-of-input print "Sammy says, "I'm a happy shark!"" ^ لحل تلك المشكلة نضع الخط المائل العكسي \ قبل كل علامة اقتباس مزدوجة داخل النص كما يلي: print "Sammy says, \"I'm a happy shark!\"" وننفذ البرنامج مرة أخرى ونلاحظ طباعة النص دون أي مشاكل: Sammy says, "I'm a happy shark!" نلاحظ بأننا لم نكن بحاجة للهروب من علامات الاقتباس المفردة في هذا المثال، وذلك لاستخدامنا علامات مزدوجة لتعريف السلسلة النصية، لذا يجب فقط الهروب من علامات الاقتباسات التي تفهمها روبي خطأً. يمكننا الاستغناء عن محارف الهروب من علامات الاقتباسات تمامًا وذلك باستخدام صيغة مختلفة لتعريف السلاسل النصية سنتعرف عليها في الخيار الثالث في الفقرة التالية. الخيار الثالث: الصيغة البديلة لتعريف السلاسل النصية استخدمنا حتى الآن علامات الاقتباس لتعريف السلاسل النصية، وتوفر روبي طريقةً أخرى لإنشاء سلاسل نصية باستخدام محارف أخرى، إذ يمكننا تعريف محرف فاصل delimiter أو محرف غير موجود ضمن السلسلة النصية وأن نحيط به قيمة السلسلة النصية بدلًا من علامات الاقتباس، وندل روبي على المحرف الذي اخترناه بذكره بعد محرف النسبة المئوية %، ففي المثال التالي اخترنا المحرف $ لتعريف السلسلة النصية: %$Sammy says, "I'm a happy shark!"$ تهرب هذه الصيغة تلقائيًا من المحارف الخاصة ضمن السلسلة النصية وينتج عن السلسلة النصية السابقة ما يلي: "Sammy says, \"I'm a happy shark!\"" ويجب الانتباه إلى تغيير المحرف الفاصل في حال وجوده ضمن السلسلة النصية، فمثلًا في المثال السابق إذا احتوى النص على المحرف $ فيجب الهروب بإضافة المحرف \ قبله ضمن النص، أو يمكن استخدام زوج من الأقواس المعقوصة Curly braces { و } لتحديد بداية ونهاية السلسلة النصية، أو الأقواس المعقوفة square braces [ و ]، أو الأقواس الهلالية parentheses ( و )، ولكن الأقواس المعقوصة هي الأكثر شيوعًا: %{Sammy says, "I'm a happy shark!"} تدعم كل تلك الصيغ ميزة تضمين القيم داخل السلسلة النصية: droplets = 5 print %{Sammy says, "I just created #{droplets} droplets!"} تُستخدم الصيغ {}Q% و {}q% أحيانًا أيضًا لتعريف السلاسل النصية في روبي، وتعمل صيغة {}Q% بالضبط مثل صيغة علامات الاقتباس المزدوجة، ما يعني عدم الحاجة للهروب من علامات الاقتباس المزدوجة داخل السلسلة النصية وإمكانية تضمين القيم داخل السلسلة النصية: droplets = 5 print %Q{Sammy says, "I just created #{droplets} droplets!"} أما صيغة {}q% فهي بديلة لصيغة علامات الاقتباس المفردة: %q{Sammy says, "I'm a happy shark!"} يُستخدم أحيانًا مع الصيغتين {}q% و {}Q% الأقواس الهلالية أو الأقواس المعقوفة بدلًا من الأقواس المعقوصة، وكما نلاحظ توفر روبي العديد من الطرق لإنشاء السلاسل النصية ويفضل استخدام صيغة تعريف موحدة ضمن الشيفرة ككل، وتفي غالبًا كلًا من الصيغتين {}Q% و {}q% بالغرض. الآن، بعد أن تعرفنا على طرق التعامل مع المحارف الخاصة سنتعرف في الفقرة التالية طريقة التعامل مع السلاسل النصية الطويلة والتي تمتد إلى عدة أسطر. السلاسل النصية الطويلة والأسطر الجديدة لإدراج سطر جديد ضمن سلسلة نصية ما يمكن استخدام محرف السطر الجديد n\، أو المحرف r\ الذي يدل على عودة المؤشر لبداية السطر وهو مفهوم أتى من أنظمة ويندوز القديمة التي كانت تحاكي طريقة الكتابة في الآلات الكاتبة اليدوية: output = "This is\na string\nwith newlines" puts output عند طباعة السلسلة النصية السابقة نلاحظ النزول إلى سطر جديد عند كل ورود للمحرف n\: This is a string with newlines توفر لنا هذه الطريقة إمكانية طباعة نص متعدد الأسطر، ولكن في حال كان النص طويلًا سيمتد على سطر واحد طويل وسيصعب قراءته والتعامل معه، ويمكن حل تلك المشكلة بعدة طرق، إذ يمكن استخدام ميزة دمج السلاسل النصية لكتابة النص الطويل على أجزاء كلًّا بسطر ضمن الشيفرة المصدرية للبرنامج: output = "This is a\n" + "longer string\n" + "with newlines." puts output يمكن أيضًا وضع الأسطر الجديدة مباشرةً داخل النص المكتوب دون الحاجة لاستخدام المحارف الخاصة على النحو التالي: output = "This is a longer string with newlines" puts output وهذه الطريقة ممكنة أيضًا عند استخدام أي صيغة بديلة لتعريف السلاسل النصية: output = %{This is a longer string with newlines} puts output نلاحظ عدم الحاجة لاستخدام المحرف n\ لإدراج سطر جديد، كما أن هذه الطريقة ستحافظ على المسافات البيضاء متضمنةً بداية الأسطر والأسطر الجديدة أيضًا: This is a longer string with newlines ولمنع ذلك يجب إزالة المسافات البيضاء الإضافية في بداية الأسطر ضمن الشيفرة كي لا تكون جزءًا من النص نفسه كما يلي: output = %{This is a longer string with newlines } يمكن أيضًا إنشاء سلاسل نصية متعددة الأسطر باستخدام صيغة تسمى heredoc كما يلي: output = <<-END This is a longer string with newlines END تدل العلامتان END->> و END على بداية ونهاية السلسلة النصية وتحافظ هذه الصيغة على المسافات البيضاء في بداية الأسطر، فإذا أردنا كتابة شيفرة برمجية مُنسقة مثلًا بداخلها فتنسيق تلك الشيفرة سيبقى كما هو وتبقى واضحة القراءة كما في المثال التالي: output = <<-END This is a longer string with newlines END سيُحتفظ بالمسافتين في بداية كل سطر في المثال السابق. تتوفر في روبي 2.3 والإصدارات الأحدث صيغةً تسمى "squiggly heredoc"، والتي تزيل تلك المسافات تلقائيًا من بداية الأسطر، وصيغتها تكون بتبديل الشرطة hyphen - بالعلامة تيلدا tilde ~ لتصبح بداية السلسلة النصية هي ~>> بدلًا من ->> على النحو التالي: output = <<~END This is a longer string with newlines and the code is indented but the output is not. END لينتج لدينا الخرج التالي: This is a longer string with newlines and the code is indented but the output is not. تدعم هذه الطريقة في روبي أيضًا ميزة تضمين قيم المتغيرات داخل السلاسل النصية، وكما لاحظنا هناك العديد من الطرق للتعامل مع الأسطر الجديدة والسلاسل النصية متعددة الأسطر في روبي، ويُفضل توحيد استخدام إحدى تلك الطرق ضمن الشيفرة البرمجية. تكرار السلسلة النصية نحتاج أحيانًا لتكرار سلسلة نصية ما عدة مرات، وتوفر روبي لذلك معامل الضرب *، والذي على العكس من معامل الجمع + فيمكن استخدامه مع الأعداد الصحيحة لتحديد مرات تكرار السلسلة النصية التي تسبقه، فمثلًا لطباعة السلسلة النصية "Sammy" تسع مرات يمكن ضرب هذه السلسلة النصية بالعدد 9 على النحو التالي: print "Sammy" * 9 لينتج الخرج التالي: SammySammySammySammySammySammySammySammySammy تفيد هذه الميزة للرسم باستخدام المحارف، لنرسم صندوقًا يحيط بعبارة ما على النحو التالي: puts "=" * 15 puts "| Hello World |" puts "=" * 15 نلاحظ كيف استفدنا من تكرار السطر العلوي والسفلي لرسم مربع يحيط بالعبارة والتي سينتج عنها التالي: =============== | Hello World | =============== الخاتمة تعرفنا في هذا المقال على السلاسل النصية في لغة روبي بالتفصيل، والطرق المختلفة للتعامل معها بدءًا من إنشاءها وصولًا إلى دمجها معًا وإدراج القيم بداخلها وطرق كتابة المحارف الخاصة مثل علامات الاقتباس فيها والأسطر الجديدة نهايةً بتكرار السلسة النصية لعدد من المرات، إذ تُعد السلاسل النصية من الأفكار المهمة في لغات البرمجة ويجب احتراف التعامل معها لحل العديد من المشاكل وتطوير البرامج. لمزيد من التفصيل، ارجع إلى صفحة النوع String في موسوعة حسوب. ترجمة -وبتصرف- للمقال How To Work with Strings in Ruby لصاحبه Brian Hogan. اقرأ أيضًا المقال السابق: أنواع البيانات في لغة روبي كتابة أول برنامج بلغة روبي السلاسل والمتغيرات في روبي
  6. تُصنف البيانات في لغات البرمجة إلى عدة أنواع يستدل الحاسوب بها للتعامل مع تلك البيانات أثناء تنفيذ البرامج، مثل تحديد العمليات الممكن تنفيذها على تلك البيانات، وهي تشبه إلى حد كبير أنواع البيانات التي نتعامل معها في حياتنا العادية، مثل أنواع الأعداد في الرياضيات، إذ توجد الأعداد الطبيعية مثل 0 و1 و2، والأعداد الصحيحة مثل -1 و0 و1، والأعداد غير الكسرية أو غير النسبية irrational numbers مثل π، بحيث يمكن جمع الأعداد من تلك الأنواع المختلفة مع بعضها لنحصل على نتيجة معينة، فمثلًا يمكن جمع العدد الطبيعي 5 مع العدد غير الكسري π: 5 + π يمكننا إبقاء المعادلة كما هي لإظهار العدد غير الكسري π، أو يمكننا تقريبه بعدد محدود من الأرقام العشرية ثم جمع تلك القيمتين معًا على النحو التالي: 5 + π = 5 + 3.14 = 8.14 لكن لا يمكن جمع نوعين مختلفين من البيانات، مثل الكلمات والأعداد مثلًا معًا: sky + 8 لا يمكن حل مثل تلك المعادلات وبالتالي لا يستطيع الحاسوب حلها أيضًا، فلا يمكن جمع بيانات من نوع كلمة مثل الكلمة "Sky" مع عدد طبيعي مثل العدد 8، لذا يجب الانتباه لنوع البيانات عند إسنادها لمتغيرات أو التعديل عليها وتنفيذ العمليات بينها مثل الجمع والطرح والضرب وغيرها. سنتعرف في هذا المقال على أهم أنواع البيانات الموجودة في لغة روبي Ruby، مثل الأعداد الصحيحة والعشرية والسلاسل النصية والرموز والمصفوفات وجداول Hash، وسنتعرف بعدها على مفهوم ديناميكية الأنواع dynamic typing والذي تعتمد عليه لغة روبي لتحديد نوع البيانات المُخزّنة ضمن المتغيرات والذي من الضروري فهمه لتجنب الأخطاء التي قد تقع خصوصًا أن المتغيرات يمكن أن تحتوي على قيمة من أي نوع من أنواع البيانات. سنتعرف في الفقرة التالية على أول نوع من البيانات وهو الأعداد الصحيحة وطرق التعامل معها في لغة روبي. الأعداد الصحيحة integers تشبه الأعداد الصحيحة integers في لغة روبي الأعداد الصحيحة في الرياضيات تمامًا، بحيث يمكن أن تحتوي على قيم أعداد موجبة أو سالبة أو تساوي الصفر، مثل الأعداد"1-" و"0" و"1"، ويمكن طباعتها على النحو التالي: print -25 ليكون الخرج ببساطة: -25 ويمكن تخزين العدد الصحيح ضمن متغير بإسناد قيمته إليه ثم طباعة ذلك المتغير على النحو التالي: my_int = -25 print my_int ويكون الخرج: -25 يمكن تنفيذ العمليات الحسابية على الأعداد الصحيحة، مثل الجمع بين عددين وطباعة النتيجة على النحو التالي: sum = 116 - 68 print sum ويكون الخرج على النحو التالي: 48 ندرج عادةً الفاصلة "," بعد كل ثلاث خانات من الأعداد الكبيرة لتسهيل قراءتها فمثلًا نكتب العدد مليون "1000000" بإدراج الفواصل كما يلي: "1,000,000"، أما في لغة روبي لا يمكن استخدام هذه الفاصلة ضمن العدد، وتُستخدم علامة الشرطة السفلية _ التي توفرها روبي لنفس الغرض وهو تسهيل قراءة الأعداد الكبيرة على النحو التالي: large_number = 1_234_567 print large_number نلاحظ عند طباعة قيمة ذلك العدد لن تُطبع الشرطة السفلية _، وستُطبع قيمة العدد الصحيح فقط: 1234567 سنتعرف في الفقرة التالية على نوع جديد من البيانات وهو الأعداد العشرية وطريقة التعامل معها. الأعداد العشرية floating-point number تُمثل الأعداد العشرية floating-point number أعدادًا حقيقية مثل الأرقام الكسرية أو غير الكسرية، وهي التي تحتوي على جزء عشري مثل العدد "9.0" أو "116.42-". يمكن طباعة الأعداد العشرية في لغة روبي تمامًا مثل طريقة طباعة الأعداد الصحيحة على النحو التالي: print 17.3 ويكون الخرج على النحو التالي: 17.3 يمكن أيضًا تعريف متغير وإسناد قيمة عشرية إليه كما يلي: my_float = 17.3 print my_float ليعطي الخرج التالي: 17.3 وكما هو الحال مع الأعداد الصحيحة، يمكن تنفيذ العمليات الحسابية على الأعداد العشرية أيضًا على النحو التالي: sum = 564.0 + 365.24 print sum ويكون الخرج: 929.24 ناتج جمع عدد عشري مع عدد صحيح في لغة روبي هو عدد عشري: sum = 564 + 365.24 print sum ويكون الخرج: 929.24 سنتعرف في الفقرة التالية على نوع مهم من أنواع البيانات في لغة روبي وهي البيانات البوليانية. البيانات البوليانية boolean تُستخدم أنواع البيانات البوليانية boolean لتمثيل القيم المتعلقة بالمنطق الرياضي والتي تُستخدم لتطوير الخوارزميات في علم الحاسوب، إذ يُمثّل هذا النوع من البيانات في لغة روبي إما بالقيمة الصحيحةtrue أو القيمة الخاطئةfalse، إذ تنتج تلك القيم عن العديد من العمليات الرياضية مثل العمليات البوليانية التالية: أكبر من 500 > 100 صحيح true 1 > 5 خاطئ false أصغر من 200 < 400 صحيح true 4 < 2 خاطئ false المساواة 5 = 5 صحيح true 500 = 400 خاطئ false كما هو الحال أنواع البيانات السابقة، يمكننا تخزين القيم المنطقيةtrue أو false ضمن متغير: result = 5 > 8 نستخدم التابع()print كما فعلنا سابقًا لطباعة قيمة المتغير البولياني: print result بما أن العدد 5 ليس أكبر من العدد 8، ستظهر النتيجة التالية: false البيانات البوليانية من أنواع البيانات الشائع استخدامها في لغة روبي ومعظم اللغات البرمجية الأخرى، وسنتعامل معها في هذه السلسلة وسنرى كيف يمكن أن تعيد التوابع والعمليات المختلفة القيم إما true أو false وكيف نستخدم هذه القيم للتحكم بمسار تنفيذ البرنامج، وسنتعرف في الفقرة التالية على السلاسل النصية وطريقة التعامل معها. السلاسل النصية strings تتكون السلاسل النصية strings من سلسلة من محرف واحد أو أكثر، والمحرف هو أي حرف أو رقم أو رمز، ويمكننا تعريف سلسلة نصية في لغة روبي بكتابة قيمتها ضمن علامتي اقتباس مفردة ' أو مزدوجة " على النحو التالي: "This is a string in double quotes." استخدمنا في مقال سابق السلاسل النصية عند كتابة أول برنامج بلغة روبي لطباعة العبارة "!Hello, World" على الشاشة، إذ أن تلك القيمة هي سلسلة نصية تتكون من مجموعة من المحارف: print "Hello, World!" كما هو الحال مع الأنواع الأخرى من البيانات، فيمكن تخزين السلاسل النصية أيضًا في متغيرات: output = "Hello, World!" ويمكن طباعة النص المخزن في المتغير باستخدام اسم المتغير على النحو التالي: print output ليكون الخرج: Hello, World! يمكن تنفيذ العديد من العمليات على السلاسل النصية -كما هو الحال بالنسبة للأرقام- للتعديل عليها، وتكمن أهمية هذا النوع من البيانات بأنه طريقة للتواصل النصي بين المستخدم والبرنامج. سنتعرف في الفقرة التالية على نوع جديد من البيانات وهو المصفوفات التي تفيدنا في التعامل مع قائمة من البيانات. المصفوفات arrays المصفوفة array هي نوع من البيانات يُمكّننا من تخزين مجموعة من القيم داخله نسميها عناصر تلك المصفوفة، ويمكن تعريف المصفوفة بكتابة قيم عناصرها بين أقواس مربعة [ ] والفصل بينها بالفاصلة ,، فمثلًا لتعريف مصفوفة من الأرقام الصحيحة نكتب التالي: [-3, -2, -1, 0, 1, 2, 3] أو مصفوفة من الأعداد العشرية: [3.14, 9.23, 111.11, 312.12, 1.05] أو مصفوفة من السلاسل النصية: ['shark', 'cuttlefish', 'squid', 'mantis shrimp'] وكما هو الحال مع أنواع البيانات الأخرى يمكننا تخزين قيمة المصفوفة ضمن متغير: sea_creatures = ['shark', 'cuttlefish', 'squid', 'mantis shrimp'] وعند طباعة قيمة أي مصفوفة: print sea_creatures سيظهر شكلها تمامًا كما هي عند تعريفها: ['shark', 'cuttlefish', 'squid', 'mantis shrimp'] يمكن الوصول إلى عنصر من عناصر أي مصفوفة باستخدام رقم الفهرس لذلك العنصر، وهو عدد يشير لترتيب ذلك العنصر ضمن المصفوفة ويبدأ من الصفر: puts sea_creatures[0] # shark puts sea_creatures[2] # squid للوصول إلى قيمة آخر عنصر من المصفوفة نستخدم رقم الفهرس السالب 1-، كما توفر لغة روبي التابعfirst.، الذي يعيد أول عنصر من المصفوفة، والتابع last. الذي يعيد آخر عنصر منها: puts sea_creatures.first # shark puts sea_creatures.last # mantis shrimp يمكن لعناصر المصفوفة الواحدة أن تكون بأنواع مختلفة من البيانات، فمثلًا يمكن تخزين سلاسل نصية ورموز وحتى مصفوفات أخرى ضمن مصفوفة واحدة: record = [ :en, "Sammy", 42, [ "coral", "reef" ] ] تتمتع المصفوفات في لغة روبي بخاصية التعديل؛ أي يمكن إضافة عناصر جديدة إليها، أو حذف عناصر منها، أو تعديل قيم العناصر المخزنة فيها. سنتعرف في الفقرة التالية على نوع جديد من البيانات وهو الرموز والتي تساعدنا في تسمية الأشياء ضمن البرنامج. الرموز Symbol الرمز Symbol هو نوع خاص من البيانات يُستخدم مثل اسم أو معرّف داخل برنامج روبي، وتتميز الرموز بأن قيمتها ثابتة ولا يمكن تعديلها بعد تعريفها، وتشبه طريقة تعريف الرمز طريقة تعريف أي متغير ولكن دون تعيين قيمة له وإضافة محرف النقطتين : قبل اسمه على النحو التالي: :time_zone نستخدم الرموز في لغة روبي لتسمية بعض الأشياء الهامة ضمن البرنامج، بينما نستخدم السلاسل النصية للنصوص التي نحتاج لتعديلها أو العمل عليها، إذ أن كل سلسلة نصية في روبي هي كائن جديد منفصل مخزن ضمن موقع منفصل في الذاكرة حتى لو تطابقت قيمها مع بعضها، بينما تتشارك الرموز المتطابقة بالقيمة بكونها كائن واحد مخزن في نفس المكان في الذاكرة. سنتعرف أكثر على استخدامات الرموز في الفقرة التالية عندما نتعرف على جداول Hash والتي تسمح لنا بربط مفاتيح بقيمها. جداول Hash جدول Hash هو مجموعة من أزواج المفاتيح والقيم تفيد في تخزين البيانات وتسمية كل منها وتسهيل الوصول إليها، ونستخدمها عادةً لتخزين بيانات متعلقة بشيء ما مثل بيانات شخص أو مستخدم، وتكون صيغة تعريفها على النحو التالي: {"first_name" => "Sammy", "last_name" => "Shark"} يمكن تخزين جدول Hash ضمن متغير بنفس طريقة إسناد الأنواع الأخرى من البيانات: user = {"first_name" => "Sammy", "last_name" => "Shark"} للوصول لقيمة ما من جدول Hash، نستخدم اسم المفتاح الخاص بتلك القيمة كما يلي: print user["first_name"] # "Sammy" print user["last_name"] # "Shark" يمكن استخدام الرموز مثل مفاتيح للقيم ضمن جدول Hash بدلًا من السلاسل النصية على النحو التالي: user = {:first_name => "Sammy", :last_name => "Shark"} يفضل دائمًا استخدام الرموز مثل مفاتيح للجداول لتقليل استخدام الذاكرة وتحسين الأداء، نظرًا لأن كل الرموز المتساوية بالقيمة تتشارك الكائن نفسه والقيمة نفسها ضمن الذاكرة، بينما سيولد لكل سلسلة نصية كائن جديد وفريد وبمكان جديد في الذاكرة، ويمكن الوصول للقيمة المقابلة لرمز ما ضمن جدول Hash باستخدام الرمز نفسه على النحو التالي: print user[:first_name] # "Sammy" print user[:last_name] # "Shark" يمكن تعريف جدول Hash بالصيغة التالية أيضًا: user = {first_name: "Sammy", last_name: "Shark"} تشبه هذه الصيغة الصيغة المستخدمة في لغة جافا سكريبت ولغات أخرى لتعريف الكائنات، وتُعرَّف المفاتيح في هذه الصيغة مثل رموز، أي يمكن الوصول للقيم في المثال السابق باستخدام الرموز first_name: و last_name: بدلًا من السلاسل النصية "first_name" و "last_name". الآن، بعد أن تعرفنا على العديد من أنواع البيانات في لغة روبي سنتعرف في الفقرة التالية كيف يتعامل روبي معها. لغة روبي ديناميكية الأنواع تمتاز لغة روبي بأنها ديناميكية الأنواع dynamic typing، أي لا يُعرّف نوع البيانات صراحةً عند إسناد قيمتها إلى متغير، بل يُحدّد نوع البيانات تلقائيًا بحسب القيمة التي خُزّنت فيه، مما يعني أن عملية فحص النوع ستجري خلال وقت التشغيل للبرنامج وليس في وقت الترجمة كما هو الحال في اللغات التي تكون ثابتة الأنواع static typing، وهناك عدة لغات شهيرة تستخدم نفس الطريقة مثل لغة بايثون ولغة جافا سكريبت. تتيح ديناميكية الأنواع إمكانية إسناد قيمة للمتغير t التالي مثلًا من أي نوع من أنواع البيانات المتاحة: t = 42 # t is an Integer t = "Sammy" # t is a String t = :sammy # t is a Symbol t = true # t is a boolean (true) t # t is nil كما تتيح هذه الميزة إمكانية تعديل القيمة المُخزنة ضمن المتغير نفسه وإسناد قيمة جديدة من نوع بيانات مختلف، ففي المثال التالي سنطلب من المستخدم إدخال قيمة عددية: print "Please enter the length of the room: " length = gets.chop وبما أن القيمة التي سيدخلها المستخدم من لوحة المفاتيح ستكون من نوع سلسلةً نصيةً دائمًا، فيجب تحويلها إلى عدد أولًا قبل إجراء العمليات الحسابية عليها، ففي اللغات ثابتة الأنواع static typing سنضطر لتعريف نوع البيانات ضمن المتغير قبل إسناد القيمة له، وبذلك علينا إنشاء متغير جديد بنوع بيانات مناسب لتخزين قيمة البيانات بعد تحويلها ولن نتمكن من إعادة استخدام نفس المتغير، ولكن في لغة روبي وبما أنها ديناميكية الأنواع فذلك ممكن على النحو التالي: # Convert the amount to a Float. length = length.to_f استخدمنا التابع to_f لتحويل قيمة السلسلة النصية إلى عدد عشري، كما يوجد التابع to_i لتحويل قيمة السلسلة النصية إلى عدد صحيح، ويمكن تحويل أغلب الكائنات في روبي إلى سلاسل نصية باستخدام التابعto_s: 42.to_s # "42" (42.5).to_s # "42.5" ["Sammy", "Shark"].to_s # "[\"Sammy\", \"Shark\"]" لا تعني ديناميكية الأنواع إمكانية تنفيذ العمليات بين أنواع البيانات المختلفة دون تحويلها إلى نفس النوع أولًا، فمثلًا سينتج عند جمع سلسلة نصية مع عدد صحيح: print 5 + "5" الخطأ التالي في الخرج: TypeError: String can't be coerced into Integer حتى لو نفذنا نفس العملية بعكس ترتيب القيم: print "5" + 5 سينتج خطأ أيضًا: TypeError: no implicit conversion of Integer into String لحل هذه المشكلة يجب تحويل السلسلة النصية إلى عدد صحيح أولًا ثم جمعها للحصول على النتيجة 10، أما إذا أردنا دمجهما معًا مثل سلاسل نصية للحصول على السلسلة النصية "55" فيجب تحويل العدد إلى سلسلة نصية قبل جمعه. من مزايا اللغات ديناميكية الأنواع المرونة في استخدام البيانات والتعامل مع المتغيرات، ولكن العيب الوحيد في ذلك هو عدم القدرة على تحديد نوع البيانات المخزن ضمن متغير ما قد جرى التعديل عليه، ولحل هذه المشكلة توفر روبي طرقًا لتحديد نوع بيانات أي قيمة مستخدمة سنتعرف عليها في الفقرة التالية. تحديد أنواع البيانات معظم القيم في لغة روبي هي كائنات، فالأعداد الصحيحة والعشرية والمصفوفات والرموز وجداول Hash كلها كائنات في روبي، ويحتوي كل منها على تابع يسمى class يعيد عند استدعائه نوع ذلك الكائن، وحتى القيم المنطقية true و false والقيمة nil كائنات أيضًا: 42.class # Integer (42.2).class # Float ["Sammy", "Shark"].class # Array true.class # TrueClass nil.class # NilClass كما يمكن استخدام تابع ?kind_of للتحقق من نوع البيانات على النحو التالي: 42.kind_of?(Integer) # true نستفيد من ذلك للتعرف على نوع البيانات المُخزنة ضمن متغير ما: # نوع القيمة المسندة واضح عند التعريف sharks = ["Hammerhead", "Tiger", "Great White"] ... # لكنه غير واضح في أماكن أخرى من البرنامج sharks.kind_of?(Hash) # false sharks.kind_of?(Array) # true يمكن استخدام هذه الطريقة أيضًا للتحقق من صحة البيانات القادمة من مصدر خارجي: if data.kind_of? String data = data.to_f end يوجد أيضًا التابع ?is_a والذي له نفس وظيفة التابع ?kind_of ولكنه أسهل بالقراءة: if data.is_a? String data = data.to_f end يساعد استخدام التوابع class و ?kind_of و ?is_a في التأكد من النوع الصحيح للبيانات الذي نتعامل معه، وهناك طرق أخرى سنتعلمها لاحقًا تغني عن الحاجة للتحقق من نوع البيانات يدويًا. الخاتمة تعرفنا في هذا المقال على العديد من أنواع البيانات التي توفرها روبي، إذ يمكّننا فهم أنواع البيانات تلك ووظائفها من التعامل معها وإجراء العمليات عليها لتطوير البرامج المختلفة، وهي من الأفكار الأساسية في لغة روبي والعديد من لغات البرمجة الأخرى. ترجمة -وبتصرف- للمقال Understanding Data Types in Ruby لصاحبه Brian Hogan. اقرأ أيضًا المقال السابق: التعليقات في لغة روبي Ruby دليلك الشامل إلى أنواع البيانات مدخل إلى البيانات وأنواعها: أنواع البيانات الأساسية السلاسل والمتغيرات في روبي
  7. التعليقات هي أسطر تتجاهلها المصرّفات compilers والمفسرات interpreters في البرامج الحاسوبية، ويمكننا الاستفادة من التعليقات لتوضيح البرامج للمبرمجين الآخرين عبر تفسير الشيفرات البرمجية ووظيفة كل جزء من البرنامج، إضافةً إلى استخدام التعليقات لشرح لماذا اخترتنا حلًا معينًا مثلًا، أو حتى لتعطيل جزء من البرنامج غير مكتمل ومنعه من التنفيذ مؤقتًا حتى إكماله أو إصلاحه. قد تبقى بعض التعليقات في الشيفرات البرمجية إلى الأبد مثل تلك التي تشرح السياق ضمن البرنامج، أو قد تكون مؤقتة مثل الملاحظات التي نتركها لأنفسنا أثناء تطوير البرنامج. سنتعرف في هذا المقال على طريقة استخدام التعليقات في برامج روبي لترك ملاحظات أو استخدامها مثل أداة لإصلاح الأخطاء. صيغة التعليقات واستخدامها تبدأ التعليقات في لغة روبي بالعلامة (#) ويُعد السطر بعدها كله تعليق على النحو التالي: # سطر تعليق في روبي يُفضّل وضع مسافة فارغة بعد رمز التعليق لتوضيح التعليق رغم أن ذلك ليس ضروريًا، وعند تنفيذ البرنامج فلن نلاحظ أي تغيير يدل على وجود التعليقات ضمن الشيفرة البرمجية، إذ يتجاهلها مفسّر روبي تمامًا لأنها موجودة لنقرأها نحن فقط وليس للحواسيب. يمكن الكتابة بأي لغة نريدها ضمن التعليقات مثل اللغة العربية أو الإنجليزية، ويُفضل اختيار اللغة المناسبة التي يفهمها كل من يعمل على المشروع، ويمكن استخدام التعليقات لتوضيح تفاصيل إضافية حول ما يحدث في كل جزء من الشيفرة البرمجية مثل الشيفرة التالية التي عملنا عليها في مقال سابق: # عرض رسالة للمستخدم puts "Please enter your name." # (حفظ القيمة المدخلة وإزالة آخر حرف (محرف السطر الجديد name = gets.chop # طباعة النتيجة على الشاشة puts "Hi, #{name}! I'm Ruby!" نلاحظ أن تلك التعليقات توضح وظيفة كل جزء من البرنامج وكيف يعمل. يمر البرنامج التالي على عناصر المصفوفة ويعرض محتوياتها مثل قائمة بصيغة HTML، ويمكن ملاحظة كيف أن التعليقات توضح ما تفعله الشيفرة أكثر: sharks = ['hammerhead', 'great white', 'dogfish', 'frilled', 'bullhead', 'requiem'] # مع إضافة مسافات في بدايتها وأسطر جديدة HTML تحويل كل عنصر في المصفوفة إلى عنصر listitems = sharks.map{ |shark| " <li>#{shark}</li>\n"} # المفتوحة، ثم طباعة مصفوفة عناصر القائمة <ul> طباعة print "<ul>\n#{listitems.join}</ul>" استخدمنا في هذا المثال توابعًا قد تكون جديدة، مثل map و join. نلاحظ هنا فائدة التعليقات، إذ توضح عمل البرنامج والخرج الناتج. لنختبر الآن البرنامج بحفظه في ملف بالاسم "sharks.rb"، ثم تنفيذه. $ ruby sharks.rb نلاحظ الخرج التالي: <ul> <li>hammerhead</li> <li>great white</li> <li>dogfish</li> <li>frilled</li> <li>bullhead</li> <li>requiem</li> </ul> نلاحظ عدم وجود التعليقات التي أضفناها، إذ يتجاهلها المفسّر تمامًا وكأنها غير موجودة؛ فدورها يقتصر على توضيح البرنامج وتساعدنا في توقع شكل الخرج عند التنفيذ، وهذا أفضل استخدام للتعليقات فهي ستساعد أي شخص يقرأها والذي قد يكون جديدًا على اللغة. يُفضل محاذاة التعليقات بنفس مستوى الإزاحة الخاص بالشيفرة التي تتعلق بها وتشرحها، فمثلًا عند شرح صنف ما تعريفه لا يحتوي على إزاحة نكتب التعليق الخاص بلا إزاحة أيضًا، والتعليقات الخاصة بالتوابع ضمن ذلك الصنف يجب أن تبدأ بنفس مستوى الإزاحة لكل تابع. لنلاحظ المثال التالي وهو للعبة Magic 8-Ball تعطي لنا إجابة عشوائية على السؤال الذي نطرحه، ونلاحظ أن التعليقات محاذية مع الشيفرة تشرحا في كل قسم: # صنف اللعبة class Eightball # إعداد الخيارات المتاحة def initialize @choices = ["Yes", "No", "All signs point to yes", "Ask again later", "Don't bet on it"] end # اختيار خيار عشوائي من الخيارات المتاحة def shake @choices.sample end end def play puts "Ask your question." # نتجاهل الدخل بما أننا لا نريده gets # نُنشئ كائن جديد من صنف اللعبة ونستخدمه للإجابة game = Game.new answer = game.shake puts answer # نسأل المستخدم في حال أراد إعادة اللعبة وتقييم الجواب puts "Want to try again? Press 'y' to continue or any other key to quit." answer = gets.chop if answer == 'y' play else exit end end # بدء اللعبة لأول مرة play دور التعليقات الأساسي هو مساعدة المبرمجين، سواء كان المبرمج هو من كتب الشيفرة البرمجية، أو شخص آخر يستخدمها أو يعمل عليها، لذا يجب أن نعامل التعليقات تمامًا كما نعامل الشيفرة البرمجية من ناحية الاهتمام بها وتحديثها وتوضيحها وتنسيقها، إذ يضر وجود تعليق مبهم أو يشرح على نحوٍ خاطئ أكثر من عدم وجود ذلك التعليق من الأساس. في بداية رحلتك كمبرمج، ستكتب الكثير من التعليقات التي تساعدك في فهم ما تفعله، ولكن مع اكتساب المزيد من الخبرة سيتغير محتوى تعليقاتك لشرح سبب وجود الشيفرة البرمجية التي تحاول شرحها بدلًا من شرح الشيفرة نفسا أو طريقة عملها، وبذلك ستكوّن فكرةً عن دور الشيفرة وما تفعله بنظرة بسيطة عليها، إلا في حال كانت الشيفرة معقدة بعض الشيء، فمثلًا التعليق التالي يشرح الشيفرة نفسها وهو ليس مفيدًا في حال كنت تعرف لغة روبي: # على الشاشة"Hello World" يطبع العبارة print "Hello World" فهو يكرر شرح ما تفعله الشيفرة، ورغم أن وجوده لن يغير أو يؤثر في عمل البرنامج إلا أنه حشو زائد عن الحاجة ولا يضيف أي قيمة جديدة للمبرمج قارئ الشيفرة، ولكن قد نحتاج أحيانًا للاستفاضة عند كتابة تعليقات وإطالة الشرح على عدة أسطر ولن يكفي سطر واحد، وهذا ما توفره التعليقات الكتلية التي سنتعرف عليها في الفقرة التالية. التعليقات الكتلية يمكننا استخدام التعليقات الكتلية Block Comments لشرح الشيفرة المعقدة أو الشيفرة التي لا نتوقع أن يكون القارئ على دراية بها، إذ يشرح هذا النوع من التعليقات أجزاء أو كل الشيفرة التي تليها، وتكون بنفس محاذاتها، وكما هو الحال في التعليقات العادية، يبدأ كل سطر منها بالمحرف (#) يليه مسافة اختيارية للتوضيح، وتُكتب تلك الأسطر خلف بعضها، ففي المثال التالي تعليق كتلي من الشيفرة المصدرية لإطار العمل Sinatra، ونلاحظ كيف يشرح السياق للمطورين الآخرين وطريقة عمل هذه الشيفرة: ... # Some Rack handlers (Thin, Rainbows!) implement an extended body object protocol, however, # some middleware (namely Rack::Lint) will break it by not mirroring the methods in question. # This middleware will detect an extended body object and will make sure it reaches the # handler directly. We do this here, so our middleware and middleware set up by the app will # still be able to run. class ExtendedRack < Struct.new(:app) def call(env) result, callback = app.call(env), env['async.callback'] return result unless callback and async?(*result) after_response { callback.call result } setup_close(env, *result) throw :async end ... ومع أن التعليقات الكتلية مفيدة لشرح الشيفرة بتفصيل أكثر، إلا أنه يفضل تجنب كثرة استخدامها، فقد تكون مجرد تكرار وحشو إضافي زائد، وبدلًا منها علينا أن نثق بخبرة المبرمجين الآخرين لفهم شيفرات روبي بأنفسهم، إلا إذا كانت تٌكتب تلك التعليقات لجمهور محدد، فيجب أن يقتصر دور التعليقات في توضيح السياق والسبب في وجود الشيفرة وليس تكرار شرح عملها. توفر روبي أيضًا صيغةً أخرى لكتابة التعليقات الكتلية على عدة أسطر، ولكنها نادرة الاستخدام: =begin تعليق على عدة أسطر يمكننا استخدام مثل هذه التعليقات للكتابة بأسطر عدة =end يبدأ التعليق بالكلمة begin= وينتهي بالكلمة end=، ويجب أن تكون تلك الكلمات في بداية السطر تمامًا دون مسافات قبلها، ولهذا السبب نادرًا ما تُستخدم، فلا يمكن محاذاتها سوى مع بداية السطر. توفّر روبي أيضًا نوعًا آخر وهو التعليقات السطرية والتي يمكن كتابتها مع الأسطر البرمجية سنتعرف عليها في الفقرة التالية. التعليقات السطرية يمكن كتابة هذا النوع من التعليقات على نفس سطر الشيفرة البرمجية وبعدها تمامًا، إذ تبدأ أيضًا بالمحرف (#)، ثم مسافة فارغة اختيارية للتوضيح على النحو التالي: [تعليق سطري عن الشيفرة # [الشيفرة البرمجية يجب استخدام التعليقات السطرية بحذر، لكنها مفيدة لشرح بعض الأجزاء المعقدة، أو غير الواضحة من الشيفرة، أو في حال احتمال نسيان وظيفة سطر معين في المستقبل، فمثلًا إذا لم يكن جميع من يعمل على المشروع بدراية كافية في مجال الرياضيات وتطبيقها في برامج روبي، فيمكننا شرح بعض الأجزاء والغاية منها، مثل الشرح التالي عن إنشاء عدد معقد ولكن بتعليق سطري: a=Complex(4,3) # (4+3i)إنشاء العدد المعقد والتعليق التالي الذي يشرح سبب اختيارنا لحل ما: pi = 3.14159 # حددنا عدد الخانات العشرية عن قصد في هذا البرنامج يفضل استخدام التعليقات السطرية عند الضرورة فقط لشرح سطر برمجي أو توفير إرشاد معين لمن يقرأ البرنامج. استخدام التعليقات أثناء الاختبار تعرّفنا في الفقرات السابقة على توظيف التعليقات لإضافة توثيق وشرح للشيفرات البرمجية، إذ يمكن استخدام ميزة التعليقات بوضع الرمز (#) في بداية أي سطر من الشيفرة لا نريد تنفيذه مؤقتًا، وذلك مفيدٌ أثناء تطوير واختبار أو تصحيح الأخطاء في البرنامج، فقد نواجه في بعض الأحيان مشاكلًا بعد إضافة أسطر جديدة من الشيفرة، ويمكننا لحصر سبب المشكلة تعليق بعض الأسطر المضافة حديثًا لمعرفة سبب الخطأ، إذ يمكننا مثلًا في مثال اللعبة السابق منع إعادة تشغيل اللعبة في حال كنا نختبر صحة عملية تقييم. يمكننا تعليق السطر من الشيفرة الذي يعيد تشغيل اللعبة مرةً أخرى لتعطيل تلك الميزة على النحو التالي: ... # Prompt to restart the game and evaluate the answer. puts "Want to try again? Press 'y' to continue or any other key to quit." answer = gets.chop if answer == 'y' # play else exit end end ... يمكن استخدام تعليق الشيفرات أيضًا أثناء تجربتنا لحلول بديلة ومعاينتها، فقد ترغب مثلًا بتجربة الطرق المختلفة الممكنة للتعامل مع المصفوفات في روبي، فنعلِّق الطريقة الحالية ونكتب بعدها طريقة جديدة ما لاختبارها وتحديد الأفضل منها: sharks = ["Tiger", "Great White", "Hammerhead"] # for shark in sharks do # puts shark # end sharks.each do |shark| puts shark end كما لاحظنا يفيد تعليق الشيفرات البرمجية في عملية تحديد الأخطاء وأثناء التطوير وتجربة حلول مختلفة، وذلك بتعليق أجزاء من البرنامج ومنعها من التنفيذ وتشغيله بصورةٍ نظامية ومعاينة الفرق. الخاتمة تعرفنا في هذا المقال على التعليقات في لغة روبي وطرق استخدامها والاستفادة منها لتوضيح قراءة الشيفرات البرمجية وفهمها من قبل المبرمجين العاملين عليها وحتى بمثابة ملاحظات مستقبلية للمبرمج الذي يكتب الشيفرة نفسه، مما يسهل العمل على المشروع أو البرنامج ويفيد كل من يعمل عليه، كما أنها تساعدك في فهم الشيفرة البرمجية عند الرجوع إليها بعد مدة طويلة ونسيان بعض التفاصيل والحلول المستخدمة. ترجمة -وبتصرف- للمقال How To Use Comments in Ruby لصاحبه Brian Hogan. اقرأ أيضًا المقال السابق: استكشاف لغة روبي باستخدام البرنامج التفاعلي IRB دليل تعلم البرمجة قواعد البرمجة ببساطة للمبتدئين دليل تنسيق شيفرات روبي Ruby
  8. يوفر برنامج روبي التفاعلي Interactive Ruby -أو اختصارًا IRB طريقةً سريعةً لاستكشاف لغة برمجة روبي وتجربة الشيفرات البرمجية دون الحاجة لإنشاء ملفات جديدة وتنفيذها، إذ يُعد برنامج IRB حلقة قراءة-تقييم-طباعة Read-Eval-Print Loop -أو ما يعرف اختصارًا REPL- وهي أداة توفرها العديد من لغات البرمجة الحديثة لتوفير طريقة سهلة للعب واستكشاف لغة البرمجة، ولاستخدامها نُنفذ الأمر irb ثم نكتب مباشرةً كود روبي ليترجم IRB الشيفرة المدخلة ويقيّمها ويعرض النتيجة. يمكن ضمن IRB الوصول لجميع المزايا ضمن روبي إضافةً لأي مكتبات أو gems مثبتة على جهازك، ويمكنك أيضًا إعداد IRB لحفظ سجل الأوامر المدخلة خلال الجلسة، وحتى أنه يوفر ميزة الإكمال التلقائي للشيفرة أثناء إدخالها. سنتعرف في هذا المقال على طريقة استخدام IRB لتنفيذ بعض الشيفرات ومعاينة نتيجة تنفيذها واستدعاء المكتبات الخارجية وحتى تخصيص جلسة IRB. تشغيل وإيقاف IRB يكفي تثبيت لغة روبي على الجهاز ليكون IRB مثبتًا وجاهزًا للاستخدام، ويمكننا تشغيله مباشرةً بتنفيذ الأمر irb من سطر الأوامر على النحو التالي: $ irb ليظهر لنا نافذة IRB: irb(main):001:0> يدل السياق الافتراضي الأعلى في برنامج روبي على أننا ضمن برنامج IRB وأن أي شيفرات سننفذها ستُنفذ ضمن السياق main، كما أنه سيعرض رقم السطر الحالي، وفي حال تثبيت روبي باستخدام RVM، فقد يكون شكل النافذة مختلفًا قليلًا، إذ سيعرض رقم الإصدار الحالي للغة روبي بدلًا من ذلك: 2.4.0 :001 > وللحصول على نفس نافذة الـ IRB ضمن الأمثلة في هذا المقال يمكن تشغيل IRB باستخدام الأمر التالي: irb --prompt inf-ruby يمكن ضمن IRB إدخال التعليمات بصيغة لغة برمجة روبي مباشرةً لنختبر ذلك بإضافة عددين معًا: irb(main):001:0> 2 + 2 نضغط على مفتاح "Enter" ليعرض IRB نتيجة تنفيذ تلك التعليمة: => 4 يشير الرمز <= في بداية السطر بأن هذه هي قيمة هي نتيجة تنفيذ عبارة روبي البرمجية السابقة، وللخروج من IRB ننفذ التعليمة exit أو نضغط على المفتاحين "CTRL+D" لنعود بذلك إلى واجهة سطر الأوامر. سنتعمق في الفقرة التالية في IRB وسنستخدمه لاستكشاف الشيفرات البرمجية. تنفيذ الشيفرات البرمجية ضمن جلسة IRB يُعد IRB وسيلةً رائعةً لتجربة الشيفرات البرمجية واختبارها سريعًا لمعرفة ما إذا كانت ستحل المشكلة المطلوبة، فمعظم الأوامر في روبي تعيد قيمةً ما عند تنفيذها وهو ما يظهر عند تنفيذ أي تعليمة في IRB، إذ سيطبع تلك القيمة على الشاشة. لنختبر ذلك بتنفيذ الأمر التالي ضمن جلسة IRB جديدة: irb(main):001:0> puts "Hello World" عند الضغط على "Enter" سنرى نتيجتين من IRB: Hello World => nil السطر الأول هو ناتج عن تنفيذ التابع puts، الذي يطبع النص الممرر له وبعده محرف لسطر جديد إلى وحدة الخرج القياسي والذي هو الشاشة عادةً. يعيد التابع puts نفسه قيمةً عند تنفيذه وذلك لأن كل تابع في روبي يجب أن يعيد قيمةً ما، والقيمة التي يعيدها التابع puts هي nil، وهذا تمامًا ما يعرضه IRB في السطر الثاني، وفي كل مرة ننفذ فيها تعليمةً برمجيةً، سيتغير رقم السطر الحالي إلى رقم سطر جديد: irb(main):001:0> puts "Hello World" Hello World => nil irb(main):002:0> يفيد عرض رقم السطر الحالي خلال عملية تصحيح الأخطاء عند تنفيذ التعليمات المعقدة، فعند حدوث أخطاء، ستشير رسالة الخطأ إلى أرقام الأسطر التي نتج عنها الخطأ، ويمكن استخدام IRB لتعريف المتغيرات وإسناد القيم لها بنفس الصيغة المستخدمة ضمن برامج روبي، فمثلًا يمكننا تنفيذ الأمر التالي ضمن جلسة IRB والضغط على "Enter": irb(main):002:0> birth_year = 1868 لنرى القيمة التي تعيدها تلك التعليمة البرمجية: => 1868 يحتوي المتغير birth_year على تلك القيمة. بما أن معظم الأوامر في روبي تُرجع قيمًا، فسيعرض IRB لنا القيمة التي تعيدها تعليمة الإسناد هنا أيضًا. لنعرف متغيرًا آخرًا بالاسم death_year على النحو التالي: irb(main):003:0> death_year = 1921 ثم نعرف المتغير age_at_death عن طريق طرح قيمة birth_year من قيمة المتغير death_year: irb(main):004:0> age_at_death = death_year - birth_year يسند IRB القيمة للمتغير الجديد ويعرض النتيجة: => 53 نلاحظ عدم حاجتنا للاستعادة بالتوابع puts أو print ضمن جلسة IRB، إذ تُطبع تلقائيًا القيم التي تعيدها التعليمات البرمجية المُنفذة. يدعم IRB كتابة الشيفرات البرمجية التي تمتد على عدة أسطر، إذ يُنفذ تلك الشيفرات البرمجية بعد اكتمال صياغتها بصورةٍ صحيحة، ففي الشيفرة البرمجية التالية نستخدم مصفوفة من أسماء الأسماك ونستدعي منها التابع select لإرجاع أسماء الأسماك التي تحتوي على الحرف "a" في اسمها، ولكتابة هذه الشفرة على عدة أسطر ضمن جلسة IRB نضغط مفتاح "Enter" بعد كل سطر منها: ["Tiger", "Great White", "Angel"].select do |shark| shark.include?("a") end سينفذ IRB الشيفرة البرمجية فقط عند اكتمال صحة صياغتها، ونلاحظ ظهور رمز النجمة * في بداية الأسطر دلالةً على عدم تنفيذ IRB للشيفرات السابقة بعد، وتتغيير القيمة صفر في نهاية اسم السطر إلى واحد للدلالة على الدخول في سياق جديد مختلف: irb(main):005:0> ["Tiger", "Great White", "Angel"].select do |shark| irb(main):006:1* shark.include?("a") irb(main):007:1> end بما أن السطر الأول يحتوي على الكلمة المفتاحية do، فإن IRB لا ينفذ أي تعليمة لاحقة حتى يصل إلى الكلمة المفتاحية end، ومن ثم سيعرض النتيجة: => ["Great White"] يمكن باستخدام IRB اختبار الشيفرات البرمجية الصغيرة لاستكشاف طريقة عملها قبل اعتمادها ضمن البرامج التي نعمل على تطويرها، كما يمكن استخدام IRB لاستدعاء المكتبات الخارجية والتعامل معها وهو ما سنتعرف عليه في الفقرة التالية. استخدام المكتبات والأمر Gem يمكنك استيراد المكتبات إلى جلسة IRB باستخدام تعليمة require تمامًا كما نفعل في برنامج روبي، ويمكن أن تكون أحد المكتبات القياسية ضمن مكتبة روبي، أو مكتبات خاصة بنا، أو مكتبات Gems وهي مكتبات روبي المنشورة ضمن المستودع Rubygems.org، والتي يمكننا تثبيتها باستخدام أمر gem؛ إذ تتضمن مكتبة روبي القياسية وحدات تمكننا من إرسال الطلبات عبر الويب مثلًا واستقبال نتائجها، ويمكن استخدام تلك المكتبة من داخل جلسة IRB تمامًا كما نفعل في برنامج روبي؛ إذ تُستخدم التعليمة require لاستيراد المكتبة Net/HTTP من مكتبة روبي القياسية بإدخال السطر التالي ضمن جلسة IRB والضغط على ENTER: require 'net/http' يعيد تنفيذ هذا السطر في IRB القيمة true، مما يدل نجاح تحميل المكتبة، ويمكننا الآن استخدامها لكتابة الشيفرة التالية لإرسال طلب إلى موقع مثلًا icanhazip.com لمعرفة عنوان IP الخارجي الخاص بنا: uri = URI.parse("http://icanhazip.com") response = Net::HTTP.get_response uri response.body بعد إدخال كل سطر من الأسطر السابقة سيعرض IRB القيمة التي تعيدها كل تعليمة منها، ونستفيد من ذلك لتصحيح الأخطاء في كل خطوة في حال حدوثها: irb(main):010:0> uri = URI.parse("http://icanhazip.com") => #<URI::HTTP http://icanhazip.com> irb(main):011:0> response = Net::HTTP.get_response uri => #<Net::HTTPOK 200 OK readbody=true> irb(main):012:0> response.body => 203.0.113.52\n فمثلًا في حال لم يعثر على المكتبة المطلوبة، ستكون القيمة التي تعيدها التعليمة مختلفة. لنختبر ذلك باستيراد مكتبة HTTParty، والتي توفر طريقة أسهل للتعامل مع طلبات HTTP: require 'httparty' نلاحظ ظهور هذه الرسالة: LoadError: cannot load such file -- httparty والتي تخبرنا بأن المكتبة التي نريدها غير متاحة، إذ أن مكتبة HTTParty منشورةٌ على أنها مكتبة gem، لذلك نحتاج لتثبيتها قبل الاستخدام، لذا نخرج من جلسة IRB باستخدام المفتاحين "CTRL+D"، أو نكتب exit للعودة إلى سطر الأوامر، ثم ننفذ الأمر gem لتثبيت مكتبة httparty: $ gem install httparty الآن، نعود لجلسة irb مرةً أخرى: $ irb ونحاول تحميل وحدة المكتبة مرةً أخرى على النحو التالي: require 'httparty` نلاحظ أن قيمة تنفيذ تلك التعليمة هذه المرة هي true، مما يدل على نجاح تحميل المكتبة. لنستخدمها الآن كما يلي: response = HTTParty.get("http://icanhazip.com") response.body سنرى نتيجة قيمة رد الطلب المرسل على النحو التالي: => 203.0.113.52\n بعد أن تعرفنا على طريقة استدعاء واستخدام أي نوع من المكتبات ضمن IRB، لنتعرف على طريقة استخدامه لاستكشاف واختبار شيفرات روبي البرمجية في الفقرة التالية. تحميل الشيفرات البرمجية ضمن IRB يمكن استخدام الخيار r- عند إنشاء جلسة IRB جديدة لتحديد المكتبات أو Gems التي نريد تحميلها مباشرةً عند بدء جلسة IRB، فمثلًا يمكن تنفيذ الأمر irb -r httparty، الذي سيبدأ جلسة IRB جديدة مع تحميل مكتبة httparty مباشرةً، ما يعني عدم الحاجة لتنفيذ التعليمة require httparty ضمن الجلسة لاستيراد المكتبة، ويمكن استخدام هذا الخيار أيضًا لتحميل شيفرة برمجية خاصة بنا ضمن الجلسة الجديدة مما يفيد عند الحاجة لاستكشاف تلك الشيفرات أو اختبارها. ننهي جلسة IRB الحالية بكتابة exit أو بالضغط على المفتاحين "CTRL+D"، ثم ننشئ ملف روبي جديد بالاسم "ip_grabber.rb"، والذي سنعرف ضمنه كائنًا IPGrabber مع تابع get الذي يعيد عنوان IP الخارجي للجهاز. سنستعين بالمكتبة HTTParty لإرسال طلب HTTP وجلب قيمة العنوان من الموقع icanhazip.com، إذ يمكننا استخدام الكائن IPGrabber ضمن برامجنا الأخرى لعزل الشيفرة الخاصة بالبرنامج عن أي تغييرات خارجية، وسنتمكن من استخدام هذا الكائن حتى بعد تبديل المكتبة التي يستخدمها لإرسال طلبات HTTP أو تغيير الموقع الذي يستخدمه لجلب عنوان IP دون الحاجة إلى تعديل أي شيفرة ضمن البرامج الأخرى. نبدأ بإضافة الشيفرة التالية إلى الملف لتعريف الصنف الجديد: require 'httparty' class IPGrabber def initialize() @url = "http://icanhazip.com" end def get response = HTTParty.get(@url) response.body.chomp # remove the \n if it exists end end نحفظ الملف ونبدأ جلسة IRB ونحمل ذلك الملف ضمنها، وبما أنه ملف محلي وليس مكتبة خارجية أو مدمجة فيجب تحديد مسار هذا الملف عند تحميله ولا حاجة لكتابة اللاحقة rb. في نهاية اسم الملف: $ irb -r ./ip_grabber يمكننا الآن -بعد انتهاء تحميل جلسة IRB الجديدة- استخدام هذا الكائن مباشرةً في الجلسة على النحو التالي: ip = IPGrabber.new ip.get نلاحظ ظهور النتيجة وهي العنوان: => 203.0.113.52 تمكّننا خاصية تحميل الشيفرات الخاصة بنا ضمن جلسة IRB من فحصها أو استدعائها للعمل بها واختبارها قبل دمجها في البرامج التي نعمل على تطويرها. الآن، بعد أن تعرفنا على طريقة تحميل والعمل مع الشيفرات في جلسة IRB، سنتعرف على طريقة تخصيص جلسة IRB وإعدادها لتناسب حاجتنا. تخصيص جلسة IRB يمكننا عبر إنشاء ملف الإعدادات بالاسم "irbrc." تخصيص جلسة IRB، مثل إضافة ميزة دعم الإكمال التلقائي والمسافات وتحديد سجل تاريخ الأوامر. لنبدأ بإنشاء هذا الملف ضمن مجلد المستخدم: $ nano ~/.irbrc نبدأ بتفعيل ميزة الإكمال التلقائي في IRB، إذ يتيح لنا ذلك ميزة استخدام المفتاح "TAB" ضمن الجلسة لإكمال أسماء الكائنات والمتغيرات وأسماء التوابع: require 'irb/completion' نضيف بعدها تفعيل ميزة حفظ تاريخ الأوامر المدخلة في ملف خارجي: IRB.conf[:SAVE_HISTORY] = 1000 بذلك ستُسجل آخر 1000 عبارة برمجية ندخلها ضمن ملف بالاسم "irb_history." في مجلد المستخدم. إضافةً لذلك، عند فتح جلسة IRB جديدة، سيُحمل تاريخ هذه التعليمات تلقائيًا، ويمكننا استخدام مفاتيح الأسهم للأعلى أو الأسفل للتنقل بين هذه التعليمات، أو استخدام CTRL+R للبحث ضمنها تمامًا كما نفعل في صدفة باش bash، ويمكننا أيضًا تحديد ملف لحفظ تاريخ التعليمات مختلف بإضافة السطر التالي لملف الإعدادات: IRB.conf[:HISTORY_FILE] = '~/your_history_filename' نضيف السطر التالي لملف الإعدادات لتفعيل ميزة إدراج المسافات تلقائيًا في بداية الأسطر، وهي ميزة مفيدة عند كتابة الأصناف والتوابع والكتل البرمجية blocks: IRB.conf[:AUTO_INDENT] = true يمكن لملف الإعدادات أن يحتوي شيفرات برمجية بلغة روبي، ما يعني إمكانية تعريف التوابع المساعدة أو استخدام require لتحميل المكتبات الإضافية، فمثلًا يمكننا تعريف التابع المساعد history إلى جلسة IRB لعرض التاريخ بإضافته على النحو ضمن ملف الإعدادات "irbrc.": def history history_array = Readline::HISTORY.to_a print history_array.join("\n") end يمكننا بعد إنشاء جلسة IRB جديدة كتابة history لعرض تاريخ IRB، وقد يحتوي التاريخ على عدد كبير من السجلات لذا يمكننا التعديل على الأمر history ليأخذ عددًا اختياريًا يعبر عن عدد الأسطر التي نود عرضها، لذا نستبدل الشيفرة الخاصة به لتأخذ معاملًا اختياريًا يسمى count وتستخدمه لتحديد عدد السجلات التي يعرضها: # history command def history(count = 0) # Get history into an array history_array = Readline::HISTORY.to_a # if count is > 0 we'll use it. # otherwise set it to 0 count = count > 0 ? count : 0 if count > 0 from = history_array.length - count history_array = history_array[from..-1] end print history_array.join("\n") end نحفظ الملف وننشئ جلسة IRB جديدة ثم نكتب history 2 لنرى فقط آخر سطرين من سجل التاريخ الموجود. يجب التذكر أنه وبالرغم من إمكانية استخدام ملف الإعدادات "irbrc." لتحميل المكتبات التي نستخدمها بصورةٍ متكررة ضمن جلسات IRB إلا أن كل مكتبة منها ستزيد وقت تحميل كل جلسة جديدة، ولتجنب ذلك يُفضّل تحميل تلك المكتبات يدويًا باستخدام require عند الحاجة إليها ضمن كل جلسة على حدى. الخاتمة يوفر لنا IRB مكانًا لاستكشاف وتجربة شيفرات روبي البرمجية بسهولة، وهو وسيلة رائعة لاستخدامها لتطوير أجزاء من البرنامج الذي نعمل عليه قبل اعتماده وحفظه ضمن ملف. الآن، بعد أن تعرفنا على IRB، يمكنك استخدامه لاستكشاف أنواع البيانات المختلفة المتاحة في روبي أو استكشاف أي مزايا أخرى واستخدام وتجربة المكتبات والتعرف عليها. ترجمة -وبتصرف- للمقال How To Use IRB to Explore Ruby لصاحبه Brian Hogan. اقرأ أيضًا المقال السابق: كتابة أول برنامج بلغة روبي كل ما تحتاج إليه لتعلم البرمجة بـ Ruby الدليل السريع إلى لغة البرمجة روبي Ruby
  9. سنكتب معًا في هذا المقال أول برنامج بلغة روبي، وبدلًا من كتابة البرنامج التقليدي "Hello, World" سنكتب برنامجًا يطلب من المستخدم إدخال اسمه، ثم يستخدم هذا الاسم في طباعة جملة تحية. الخرج التالي هو مثال عن البرنامج الذي سنطوره في هذا المقال: Please enter your name. Hassan Hello, Hassan! I'm Ruby! سنحتاج بدايةً لبيئة تطوير روبي مثبتة، ويمكنك الاطلاع على المقالات السابقة في سلسلة البرمجة بلغة روبي للتعرف على طريقة إعداد بيئة تطوير روبي. كتابة برنامج !Hello, World سنكتب بدايًة البرنامج التقليدي "!Hello, World"، لذلك نفتح أي محرر نصوص عبر سطر الأوامر مثل نانو nano ونُنشئ ملفًا جديدًا على النحو التالي: $ nano hello.rb بعد فتح الملف نكتب البرنامج التالي: puts "Hello, World!" عند تنفيذ البرنامج سيطبع التابع puts المتاح في روبي سلسلة الحروف المُمررة له بين علامتي التنصيص على الشاشة، وتدعى هذه السلسلة من الحروف بالسلاسل النصية string. توفر لغة روبي عدة توابع جاهزة، مثل التابع puts، إذ يمكن استخدام تلك التوابع مباشرةً في البرنامج كما يمكننا تعريف توابع جديدة خاصة بنا. الآن، نحفظ التغييرات ونخرج من المحرر بالضغط على المفتاحين "Ctrl+X" ولتأكيد حفظ الملف نضغط على المفتاح "y" ثم "Enter". سنشغّل في الفقرة التالية البرنامج لتجربته ونرى النتيجة. تشغيل برنامج روبي بعد كتابتنا لبرنامج "!Hello, World" في الفقرة السابقة، ننفذ ذلك البرنامج باستخدام الأمر التالي: $ ruby hello.rb سيظهر النص "!Hello, World" على الشاشة، إذ يقرأ مترجم لغة روبي بتنفيذ الأمر ruby الملف المحدد ويعاين محتواه ويترجمه، ثم يبدأ بتنفيذ الأمر "!puts "Hello, World باستدعاء الدالة puts، ويمرر لها النص "!Hello, World" مثل معامل لتلك الدالة، إذ تدعى القيم التي تمرر لأي دالة بالوسيط argument، ولاحظ أن علامات الاقتباس التي تحيط بالنص "!Hello, World" لا تطبع على الشاشة فهي تستخدم فقط لإخبار روبي بأن تلك القيمة هي سلسلة نصية بتحديد بداية ونهاية السلسلة بعلامات الاقتباس تلك. الآن، بعد نجاح تنفيذ البرنامج سنطوّره في الفقرة التالية ليصبح تفاعليًا. طلب الدخل من المستخدم كتبنا في الخطوة السابقة برنامجًا يطبع نصًا ثابتًا على الشاشة، دون أن يتفاعل البرنامج مع المستخدم، وسنطلب في هذه الفقرة من المستخدم أن يدخل قيمةً، وسنتعرف على طريقة استخدامها في البرنامج، ونبدأ بكتابة برنامج جديد بفتح محرر النصوص نانو وإنشاء ملف جديد كما فعلنا سابقًا: $ nano greeting.rb نضيف السطر التالي لنطلب من المستخدم إدخال اسمه: puts "Please enter your name." استخدمنا التابع puts مرةً أخرى لطباعة نص السؤال على الشاشة، وسنضيف السطر التالي لاستقبال القيمة التي سيدخلها المستخدم: puts "Please enter your name." name = gets يخبر التابع gets البرنامج بانتظار دخل المستخدم من لوحة المفاتيح، إذ سيتوقف عندها البرنامج عن العمل لحين انتهاء المستخدم من إدخال أي نص يريده، وسيتابع البرنامج عمله بعد ضغط المستخدم على مفتاح "Enter" من لوحة المفاتيح، لتُحوّل كل تلك الضغطات على لوحة المفاتيح بما فيها المفتاح "Enter" إلى سلسلة من المحارف. بما أننا سنستخدم سلسلة المحارف تلك ضمن خرج البرنامج، سنحفظها ضمن متغير جديد بالاسم name باستخدام معامل الإسناد = ليخزن بذلك روبي تلك السلسلة في ذاكرة الحاسوب لحين انتهاء تنفيذ البرنامج، والآن نضيف السطر التالي لطباعة النتيجة النهائية: puts "Please enter your name." name = gets puts "Hi, #{name}! I'm Ruby!" نلاحظ استخدام التابع puts لطباعة سلسلة نصية مرةً أخرى، ولكن هذه المرة مررنا له سلسلةً نصيةً تحتوي على قيمة المتغير name ضمنها باستخدام ميزة في روبي لإدخال قيمة متغير ضمن سلسة نصية مباشرةً تدعى استيفاء السلسلة النصية string interpolation، إذ ستستبدل كلمة {name}# بالقيمة المحفوظة ضمن المتغير name، والتي يجب أن تكون اسم المستخدم الذي أدخله. الآن، نحفظ الملف ونخرج من محرر نانو بالضغط على مفتاحي "CTRL+X"، ثم تأكيد الحفظ بالضغط على "y" ثم مفتاح "Enter"، ولنشغل البرنامج ونختبره باستخدام الأمر التالي: $ ruby greeting.rb سيطلب البرنامج من المستخدم إدخال اسمه بعد الإدخال نضغط "Enter" ونلاحظ النتيجة: Please enter your name. Hassan Hi, Hassan ! I'm Ruby! بدلًا من طباعة !Hi, Hassan! I'm Ruby، طُبع فراغًا بعد الاسم المستخدم، والسبب في ذلك أن البرنامج استقبل جميع الضغطات على لوحة المفاتيح بما فيها المفتاح "Enter" في النهاية لإكمال الدخل، مما يؤدي أن السلسلة النصية ستنتهي بمحرف خاص يدل على طباعة سطر جديد، فالنتيجة التي يعرضها البرنامج هي فعلًا ما قد أُدخل من قبل المستخدم بما في ذلك محرف السطر الجديد. لحل تلك المشكلة نفتح ملف البرنامج "greeting.rb" ضمن محرر النصوص: $ nano greeting.rb ونبحث عن السطر التالي: name = gets نعدله ليصبح: name = gets.chop بالاستفادة من استدعاء التابع chop في روبي على السلسلة النصية المدخلة من قبل المستخدم باستخدام gets، سيُزال آخر محرف من السلسلة النصية وفي حالتنا هو محرف السطر الجديد الناتج عند الضغط على المفتاح "Enter". الآن، نحفظ الملف ونخرج من نانو بالضغط على CTRL+X ثم على المفتاح "y" لتأكيد حفظ الملف ونشغل البرنامج مرةً أخرى: $ ruby greeting.rb نلاحظ هذه المرة بعد إدخال الاسم والضغط على "Enter" طباعة عبارة التحية على سطر واحد كما نريد: Please enter your name. Sammy Hi, Sammy! I'm Ruby! وبذلك نكون قد طورنا برنامجًا بلغة روبي يقرأ دخلًا من المستخدم ويطبعه على الشاشة. الخاتمة تعرفنا في هذا المقال طريقة طلب الدخل من المستخدم في روبي ومعالجة ذلك الدخل لعرض النتيجة، ويمكن تطوير البرنامج أكثر، إذ يمكن مثلًا الطلب من المستخدم لونه المفضل وجعل البرنامج يطبع جملة "لونك المفضل هو الأحمر". ترجمة -وبتصرف- للمقال How To Write Your First Ruby Program لصاحبه Brian Hogan. اقرأ أيضًا المقال السابق: تثبيت إطار Ruby on Rails في أوبنتو لينكس الدليل السريع إلى لغة البرمجة روبي Ruby تعرّف على لغة البرمجة Ruby
  10. يعد روبي أون ريلز Ruby on Rails -أو اختصارًا ريلز Rails- من أشهر أطر العمل بلغة روبي Ruby المستخدمة في تطوير المواقع وتطبيقات الويب بسهولة وسرعة، إذ يمكن تثبيت إطار العمل باستخدام أداة سطر الأوامر rbenv، التي تتيح إمكانية إنشاء بيئة لتطوير التطبيقات باستخدام روبي أون ريلز والتبديل بين نسخ روبي المختلفة، كما تمكّنك من تخصيص وتحديد نسخة روبي مختلفة لكل تطبيق تطوره على حدى بغض النظر عن النسخة الافتراضية العامة ضمن النظام، كما تمكّنك من تحديد نسخة روبي محددة لكل مستخدم على حدى مع ترك إمكانية تغيير تلك النسخة باستخدام متغيرات البيئة. سنتعرف في هذا المقال على طريقة تثبيت روبي أون ريلز باستخدام rbenv و gem، إذ سنبدأ بتثبيت الحزم المطلوبة لعمل rbenv ثم روبي وبعدها سنثبت الإضافة ruby-build لنتمكن من تثبيت أحد إصدارات روبي المتوفرة. بعد ذلك، سنستخدم gem لتثبيت إطار ريلز لنتمكن من استخدام روبي ضمنه من أجل تطوير تطبيقات الويب، وسنتعلم أيضًا طريقة التحقق من توفر التحديثات لنسخة rbenv المثبتة، وطريقة إزالة تثبيت نسخ روبي وأيضًا rbenv. ستحتاج لتطبيق الخطوات في هذا المقال إلى ما يلي: نظام خادم أوبنتو 22.04 مثبت مع إمكانية الوصول لحساب مستخدم يمكنه تنفيذ الأمر sudo وجدار ناري مثبت. نسخة نود Node.js مثبتة على النظام، إذ تحتاج بعض مزايا ريلز، مثل ميزة أنبوب الموارد Asset Pipeline لبيئة تشغيل جافا سكريبت لعملها. تثبيت أداة rbenv واعتماديتها تعتمد لغة روبي على عدد من الحزم التي يمكنك تثبيتها من خلال مدير الحزم، وحالما تثبّت هذه الحزم، يمكنك تثبيت rbenv واستخدامها لتثبيت روبي. نبدأ بتنفيذ أمر تحديث قائمة الحزم على النظام: $ sudo apt update ثم نثبّت الاعتماديات المطلوبة تثبيت روبي: $ sudo apt install git curl libssl-dev libreadline-dev zlib1g-dev autoconf bison build-essential libyaml-dev libreadline-dev libncurses5-dev libffi-dev libgdbm-dev بعد ذلك، يمكننا تثبيت rbenv باستخدام الأمر curl لتنزيل النص البرمجي المستخدم لتثبيته الموجود على غيت هب GitHub وتمريره مباشرةً إلى الأمر bash لتنفيذه على النحو التالي: $ curl -fsSL https://github.com/rbenv/rbenv-installer/raw/HEAD/bin/rbenv-installer | bash نضيف المسار "rbenv/bin./~" إلى المتغير PATH$ لنتمكن من استخدام أداة سطر الأوامر rbenv، وذلك بتعديل الملف bashrc./~ ليُطبق التعديل ضمن جلسات الطرفية اللاحقة: $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc ثم نضيف أمر تحميل rbenv إلى نفس الملف مجددًا على النحو التالي: $ echo 'eval "$(rbenv init -)"' >> ~/.bashrc ولتطبيق تلك التعديلات على جلسة الطرفية الحالية ننفذ الأمر التالي: $ source ~/.bashrc نستخدم الأمر type لنتأكد من تطبيقها وتوفر الأمر rbenv، إذ سيعرض هذا الأمر معلومات حول rbenv على النحو التالي: $ type rbenv ليظهر لنا الخرج التالي: rbenv is a function rbenv () { local command; command="${1:-}"; if [ "$#" -gt 0 ]; then shift; fi; case "$command" in rehash | shell) eval "$(rbenv "sh-$command" "$@")" ;; *) command rbenv "$command" "$@" ;; esac } وبذلك نكون ثبتنا كلًا من الأداتين rbenv و ruby-build، وسنبدأ في الفقرة التالية بتثبيت روبي. تثبيت روبي باستخدام ruby-build بعد أن ثبتنا الإضافة ruby-build، يمكننا تثبيت أي نسخة من روبي نحتاجها عبر سطر الأوامر ونبدأ بعرض النسخ المتاحة بتنفيذ الأمر التالي: $ rbenv install -l ليظهر لنا قائمة بالنسخ المتوفرة: 2.7.7 3.0.5 3.1.3 3.2.0 jruby-9.4.0.0 mruby-3.1.0 picoruby-3.0.0 truffleruby-22.3.1 truffleruby+graalvm-22.3.1 Only latest stable releases for each Ruby implementation are shown. Use 'rbenv install --list-all / -L' to show all local versions. لنختار نسخة روبي 3.2.0 ونثبتها كما يلي: $ rbenv install 3.2.0 تستغرق عملية التنزيل والتثبيت بعض الوقت لإنهائها، وبعد ذلك يمكننا تعيين تلك النسخة على أنها نسخة افتراضية باستخدام الأمر الفرعي global على النحو التالي: $ rbenv global 3.2.0 ونتحقق من ذلك بعرض نسخة روبي الحالية: $ ruby -v ليظهر لنا معلومات النسخة التي اخترناها سابقًا على النحو التالي: $ ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux] وبذلك نكون قد ثبتنا نسخة من نسخ روبي وعيناها على أنها نسخة عامة افتراضية وأصبحت جاهزة للعمل عليها. سنعد في الفقرة التالية مكتبة gems وإطار ريلز التعامل مع المكتبات Gems الطريقة التي تنشر بها مكتبات روبي تسمى gems ويمكن استخدام الأمر gem لإدارتها وأيضًا لتثبيت إطار ريلز، فعند تثبيت أي مكتبة منها ينشأ لها ملفات توثيق محلي، وقد تستغرق تلك العملية وقتًا لذا يمكننا إلغاؤها بإنشاء ملف إعدادات في المجلد "gemrc./~" وإضافة تعليمة ضمنه بتنفيذ الأمر التالي: $ echo "gem: --no-document" > ~/.gemrc ونبدأ بتثبيت أول أداة وهي Bundler، التي تفيد في إدارة الاعتماديات ضمن المشروع ويعتمد عليها إطار ريلز في عمله: $ gem install bundler ليظهر لنا الخرج التالي: Fetching bundler-2.4.5.gem Successfully installed bundler-2.4.5 1 gem installed يمكننا استخدام الأمر gem env (الأمر الفرعي env هو اختصار للأمر environment)، لعرض معلومات عن البيئة والاعدادات الحالية للمكتبات gems، إذ يمكننا مثلًا عرض مسار تثبيت الاعتماديات على النظام بتنفيذ الأمر الفرعي home على النحو التالي: $ gem env home ليظهر لنا المسار على النحو التالي: /home/hassan/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0 بعد أن ثبتنا gems يمكننا الآن تثبيت إطار ريلز وهو ما سنشرحه في الفقرة التالية. تثبيت ريلز لتثبيت ريلز نُنفذ الأمر gem install مع الخيار v- لتحديد الإصدار المطلوب إذ سنستخدم في هذا المقال الإصدار 7.0.4: $ gem install rails -v 7.0.4 يُثبت الأمر السابق المكتبة التي حددناها مع اعتمادياتها، وبما أن ريلز إطار عمل لتطوير تطبيقات الويب المعقدة لذا فهو يحتوي على العديد من الاعتماديات، وهو سبب استغراق تنفيذ الأمر السابق بعض الوقت وسينتج عنه رسالة تفيد بتثبيت ريلز بنجاح مع اعتمادياته: ... Successfully installed rails-7.0.4 35 gems installed يمكننا استعراض الإصدارات المتاحة لاختيار تثبيت إصدار مختلف من ريلز عن طريق البحث باستخدام الأمر search، الذي سيعرض قائمة بالإصدارات المتاحة للتنزيل، ويمكننا الاختيار منها وتثبيت أحد تلك الإصدارات، ففي الأمر التالي سنختار الإصدار 4.2.7: $ gem search '^rails$' --all $ gem install rails -v 4.2.7 وإذا أردنا تثبيت أحدث إصدار من ريلز يمكننا تنفيذ نفس الأمر لكن بدون تحديد رقم الإصدار: $ gem install rails إذ سيُنشئ rbenv مجلدًا لملفات shims، الذي يشير إلى الملفات المستخدمة من قبل إصدار روبي المُفعل حاليًا. يدير rbenv من خلال الأمر الفرعي rehash ملفات shims ضمن ذلك المجلد، وذلك لمطابقة كل أمر من أوامر روبي عبر كل إصدار مثبت من روبي على الجهاز الخاص بنا. عند تثبيت إصدار جديد من روبي أو مكتبة gem توفر أوامرًا يمكن تنفيذها مثل ريلز، يجب تنفيذ الأمر التالي: $ rbenv rehash للتحقق من تثبيت ريلز بنجاح يمكنك طباعة رقم إصداره باستخدام الأمر التالي: $ rails -v فإذا انتهى التثبيت بنجاح سيظهر لنا رقم إصدار ريلز المُثبت: Rails 7.0.4 الآن، يمكننا البدء في اختبار وتثبيت روبي ضمن ريلز وتطوير تطبيقات الويب باستخدامه، وسنستعرض في الفقرة التالية طريقة تحديث rbenv لآخر نسخة متوفرة. تحديث rbenv بما أننا ثبتنا rbenv يدويًا باستخدام Git، يمكننا تحديثه لآخر إصدار باستخدام الأمر git pull ضمن المجلد rbenv./~ على النحو التالي: $ cd ~/.rbenv $ git pull وبذلك نتأكد من استخدام أحدث إصدار متاح من rbenv. إلغاء تثبيت إصدارات روبي قد تتراكم الإصدارات الإضافية التي قد ننزلها من روبي ضمن المجلد "rbenv/versions./~"، ولحل تلك المشكلة يمكننا استخدام الأمر الفرعي uninstall الذي توفره الإضافة ruby-build لإزالة الإصدارات السابقة التي لا نحتاج لها، فمثلًا يمكن استخدام الأمر التالي لإلغاء تثبيت إصدار روبي بنسخة 3.2.0: $ rbenv uninstall 3.2.0 يفيد استخدام أمر إلغاء تثبيت الذي يوفره rbenv بتنظيف ذلك المجلد وإزالة الإصدارات القديمة من روبي لنبقي فقط على ما نحتاج لاستخدامه حاليًا. إلغاء تثبيت rbenv يمكننا إزالة rbenv من نظام التشغيل في حال عدم الحاجة لاستخدامه، وذلك بفتح الملف "bashrc./~" ضمن أي محرر للنصوص مثل نانو nano على النحو التالي: $ nano ~/.bashrc ونبحث عن السطرين التاليين ونحذفهما من الملف: ... export PATH="$HOME/.rbenv/bin:$PATH" eval "$(rbenv init -)" بعد حذف هذين السطرين نحفظ الملف ونخرج من المحرر بالضغط على المفتاحين "CTRL + X" ثم "Y" و "Enter" لتأكيد حفظ الملف، ويمكننا بعدها إزالة rbenv وجميع إصدارات روبي المثبتة باستخدام الأمر التالي: $ rm -rf `rbenv root` ستطبق هذه التغييرات ضمن الجلسة بعد تسجيل الخروج وتسجيل الدخول مرة أخرى. الخاتمة تعلمنا في هذا المقال كيفية تثبيت rbenv والأمر gem لتثبيت إطار عمل روبي أون ريلز كاملًا، وبذلك يمكننا إنشاء مشاريع تطوير تطبيقات الويب الجديدة. ترجمة -وبتصرف- للمقال How To Install Ruby on Rails with rbenv on Ubuntu 22.04 لأصحابه Brian Hogan و Lisa Tagliaferri و Jeanelle Horcasitas. اقرأ أيضًا المقال السابق: تثبيت روبي وإعداد بيئة برمجة محلية في أوبنتو لينكس مدخل إلى إطار العمل Ruby on Rails كل ما تحتاج إليه لتعلم البرمجة بـ Ruby توثيق روبي أون ريلز العربي
  11. يمكنك استخدام لغة البرمجة الديناميكية روبي Ruby في عدة مجالات، مثل النصوص البرمجية وتطوير الألعاب وتطبيقات الويب، وعن تاريخ هذه اللغة فقد جرى إصدارها عام 1993 في اليابان واشتُهرت في عام 2005 على أنها لغة برمجة تطبيقات الويب بطرف الخادم، إذ صُممت روبي على أنها لغة سهلة الاستخدام خصوصًا للمبتدئين وقوية في نفس الوقت قادرة على إنشاء الأنظمة المعقدة، لذا فمهما كان مستواك البرمجي فتجربة هذه اللغة تستحق الاهتمام. سنتعرف في هذا المقال على إحدى أسهل طرق تثبيت روبي ضمن نظام التشغيل أوبنتو Ubuntu من لينكس باستخدام مدير إصدارات روبي Ruby Version Manager ويختصر إلى RVM، الذي يساعدنا في تنزيل وتثبيت آخر نسخة من روبي مع المكتبات التي تحتاجها، إذ سنجهز بيئةً برمجيةً محلية على جهاز بنظام تشغيل لينكس باستخدام سطر الأوامر ونختبرها بكتابة برنامج روبي بسيط، ويمكنك تطبيق نفس الخطوات في هذا المقال ضمن أي توزيعة لينكس ديبيان Debian أخرى، كما يمكنك متابعة الخطوات وتنفيذها على نظام تشغيل أوبنتو 22.04 والتأكد من تنفيذ الأوامر وذلك من خلال حساب بصلاحيات مدير والتأكد من وجود اتصال بالإنترنت على الجهاز. استخدام الطرفية سنستخدم سطر الأوامر command line لتنفيذ الأوامر وتثبيت روبي، وهي واجهة نصية تمكنك من التعامل مع جهازك بكتابة أوامر نصية وظهور نتيجتها نصيًا أيضًا، وهي بديلٌ عن الواجهة المرئية التي نستخدم فيها مؤشر الفأرة للضغط على الأزرار والتطبيقات للتعامل مع الحاسوب. يُدعى سطر الأوامر أيضًا باسم الصدفة shell، التي تتيح لنا أتمتة العديد من المهام اليومية على الحاسوب وهي من أهم الأدوات التي يجب على المبرمج إتقانها، وسنبدأ في الفقرة التالية باستخدامها لتثبيت مدير إصدارات روبي RVM والذي سيُثبت روبي وكل ما يلزمها. تثبيت RVM وروبي لنبدأ بتثبيت RVM والذي سيؤتمت عملية إعداد بيئة روبي ضمن نظام أوبنتو، إذ أن أسهل وأسرع طريقة لتثبيته هي عبر تنفيذ النص البرمجي المتاح على موقع RVM، إذ يمكنك باستخدام الأمر gpg جلب المفتاح العام من خادم RVM والذي يُستخدم لتوقيه كل إصدار جديد من RVM، ما يتيح إمكانية التحقق من أن إصدار RVM الذي نحاول تنزيله هو إصدار أصلي وصحيح، ويمكنك ذلك بتنفيذ الأمر التالي: $ gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB وفي حال حدوث مشاكل بتنفيذ الأمر السابق يمكنك تجربة الأمر التالي: $ command curl -sSL https://rvm.io/mpapis.asc | gpg2 --import - $ command curl -sSL https://rvm.io/pkuczynski.asc | gpg2 --import - يمكن باستخدام الأمر curl تنزيل النص البرمجي لتثبيت RVM، وسنبدأ أولًا بتثبيت ذلك الأمر في حال لم يكن مثبتًا: $ sudo apt-get install curl عند تنفيذه، ستُسأل عن كلمة مرور حسابك قبل التثبيت، وستلاحظ عند كتابة كلمة المرور عدم ظهور المحارف التي تكتبها ضمن الطرفية وهي ميزة أمان لإخفاء كلمات المرور عندما تدخلها ضمن الطرفية، لذا يمكنك كتابة الكلمة بصورةٍ طبيعية حتى لو لم ترى المحارف التي تدخلها، ثم اضغط المفتاح Enter ليُثبت البرنامج. بعدها سنستخدم curl لتنزيل النص البرمجي لتثبيت RVM من موقع الخاص به من خلال الأمر التالي، ولاحظ محرف \ في بداية الأمر وهو ضروري لتنفيذ الأمر الأصلي وليس أي تسميات لأوامر أخرى تطابقه: $ \curl -sSL https://get.rvm.io -o rvm.sh الخيارات المُمررة للأمر السابق مهمة لذلك سنشرح كل منها على النحو التالي: الخيار s- اختصارًا للأمر silent--: يخبر الأمر curl ألا يظهر شريط تقدم عملية إرسال الطلب. الخيار S- اختصارًا للأمر show-error--: يخبر الأمر curl بإظهار رسائل خطأ فشل الطلب. الخيار L- اختصارًا للأمر location--: يخبر الأمر curl بمعالجة طلبات إعادة التوجيه التي قد يرسلها الخادم في حالات انتقال الملف المطلوب لعنوان آخر، إذ سيعيد إرسال نفس الطلب للعنوان الجديد. يمكنك معاينة محتوى النص البرمجي بعد انتهاء التنزيل بتنفيذ الأمر التالي: $ less rvm.sh يمكنك استخدام الأسهم التنقل وتصفح محتوى ذلك الملف، وبعد الانتهاء يمكنك الضغط على q للخروج والرجوع إلى الطرفية، والآن يمكنك تنفيذه لتثبيت آخر إصدار مستقر من RVM على النحو التالي: $ cat rvm.sh | bash -s stable سينتج عن تنفيذ هذا الأمر إنشاء مجلد جديد بالاسم "rvm." ضمن المجلد الأساس home للمستخدم الحالي، إذ ستُثبت ضمنه روبي وكل المكونات التي تحتاجها مع البرنامج التنفيذي rvm الذي سنستخدمه لتثبيت روبي، بحيث سيُضاف للملف "bashrc." المسار "rvm/bin." ضمن متغير البيئة PATH وذلك لنتمكن من تنفيذ الأمر rvm عبر سطر الأوامر بسهولة، ولتفعيل تلك التعديلات يجب تنفيذ الأمر التالي أولًا: $ source ~/.rvm/scripts/rvm والآن يمكننا تنفيذ الأمر rvm لتثبيت آخر نسخة من روبي على النحو التالي: $ rvm install ruby --default لتُنزّل وتُثبت بذلك روبي ومكوناتها وتُعيّن تلك النسخة على أنها نسخة افتراضية ضمن النظام لاستخدامها لتجنب التعارض مع أي نسخة أخرى قد تكون مُثبتة مسبقًا على جهازك. قد تستغرق هذه العملية بعض الوقت، وفي حال واجهت مشاكل تأكد من تثبيت Homebrew على جهازك بتنفيذ الأمر التالي: $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" سيُثبت الأمر أي متطلبات ناقصة لديك وقد يسألك أيضًا عن كلمة المرور لحسابك، وسيظهر عن تنفيذ أمر تثبيت روبي خرجًا مشابهًا للتالي: Searching for binary rubies, this might take some time. Found remote file https://rvm_io.global.ssl.fastly.net/binaries/ubuntu/16.04/x86_64/ruby-2.4.0.tar.bz2 Checking requirements for ubuntu. Installing requirements for ubuntu. Updating system.... Installing required packages: gawk, libssl-dev, zlib1g-dev, libyaml-dev, libsqlite3-dev, sqlite3, autoconf, libgmp-dev, libgdbm-dev, libncurses5-dev, automake, libtool, bison, libffi-dev, libgmp-dev, libreadline6-dev.................. Requirements installation successful. وبعد الانتهاء من تثبيت المتطلبات سيبدأ RVM عملية تثبيت روبي ويظهر خرجًا مشابهًا للتالي: ruby-2.4.0 - #configure ruby-2.4.0 - #download % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 16.4M 100 16.4M 0 0 4828k 0 0:00:03 0:00:03 --:--:-- 4829k ruby-2.4.0 - #validate archive ruby-2.4.0 - #extract ruby-2.4.0 - #validate binary ruby-2.4.0 - #setup ruby-2.4.0 - #gemset created /home/brian/.rvm/gems/ruby-2.4.0@global ruby-2.4.0 - #importing gemset /home/brian/.rvm/gemsets/global.gems.............................. ruby-2.4.0 - #generating global wrappers........ ruby-2.4.0 - #gemset created /home/brian/.rvm/gems/ruby-2.4.0 ruby-2.4.0 - #importing gemsetfile /home/brian/.rvm/gemsets/default.gems evaluated to empty gem list ruby-2.4.0 - #generating default wrappers........ بذلك تكون قد ثُبتت آخر نسخة من روبي لديك مع بعض الأدوات الأخرى، مثل irb وهي طرفية روبي تفاعلية سنتعرف عليها في مقال لاحق من هذه السلسلة، والبرنامج rake لأتمتة تنفيذ النصوص البرمجية، والبرنامج gem، الذي سنستخدمه لتثبيت وتحديث مكتبات روبي بكل سهولة ضمن المشاريع. للتأكد من رقم النسخة المُثبتة من روبي، ننفذ الأمر التالي: $ ruby -v سيظهر رقم نسخة روبي المثبتة لديك بخرج يشبه ما يلي: ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-linux] قبل تجربة روبي، يجب التأكد أن الطرفية عند فتحها تُنفذ صدفة تسجيل دخول، إذ أن RVM عدل الملف bash_profile. لتمكين استخدام نسخة روبي الذي ثبتها وذلك فقط ضمن صدفة تسجيل الدخول. سنختبر في الفقرة التالية روبي ببرنامج بسيط جدًا. كتابة برنامج بسيط كما هو معتاد عند تجربة لغة برمجة جديدة فأول برنامج نكتبه مهمته طباعة النص "Hello, World" لنتأكد بذلك من صحة تثبيت كل شيء وإمكانية تنفيذ البرامج بتلك اللغة، لذا نبدأ بإنشاء ملف جديد بالاسم hello.rb باستخدام محرر نانو nano: $ nano hello.rb ونكتب التعليمة التالية ضمن الملف: puts "Hello, World!" ثم نخرج من المحرر بالضغط على "Ctrl+X" ثم نضغط على المفتاح "Y" لتأكيد حفظ الملف، ثم ننفذ ملف البرنامج على النحو التالي: $ ruby hello.rb ليظهر لنا الخرج المطلوب ضمن الطرفية: Hello, World! بذلك تأكدنا أن بيئة برمجة روبي تعمل بنجاح ويمكننا استخدامها لتطوير البرامج والمشاريع باستخدام هذه اللغة. الخاتمة بعد أن تعرفنا على طريقة تجهيز بيئة للبرمجة بلغة روبي، سنتعرف في المقالات التالية أكثر على تلك اللغة عبر تجربة كتابة أول برنامج بلغة روبي، إذ أن أفضل طريقة لتعلم أي لغة برمجية هي بكتابة البرامج عمليًا وتنفيذها. ترجمة -وبتصرف- للمقال How To Install Ruby and Set Up a Local Programming Environment on Ubuntu 22.04 لصاحبته Milecia McGregor. اقرأ أيضًا كيف تثبّت Ruby على ويندوز 10 الدليل السريع إلى لغة البرمجة روبي Ruby توثيق لغة روبي
×
×
  • أضف...