بناء جملة روبي
تتشابه بنية لغة البرمجة روبي إلى حد كبير مع بنية لغتي بيرل وبايثون . تُعرَّف الأصناف والأساليب باستخدام الكلمات المفتاحية، بينما يمكن تعريف كتل التعليمات البرمجية باستخدام الكلمات المفتاحية أو الأقواس المعقوفة. على عكس بيرل، لا يُشترط وضع علامة (-) قبل المتغيرات . عند استخدامها، تُغيّر العلامة نطاق المتغير. عمليًا، لا يوجد فرق بين التعبيرات والعبارات . [ 1 ] [ 2 ] تُعتبر فواصل الأسطر مهمة وتُستخدم كنهاية للعبارة؛ ويمكن استخدام الفاصلة المنقوطة كبديل. على عكس بايثون، لا تُعتبر المسافة البادئة مهمة.
من بين الاختلافات بين روبي وبايثون وبيرل، أن روبي تُبقي جميع متغيرات مثيلاتها خاصة تمامًا بالفئة، ولا تُتيح الوصول إليها إلا من خلال دوال الوصول ( getter attr_writer، attr_readersetter، إلخ). على عكس دوال "getter" و"setter" في لغات أخرى مثل C++ أو جافا ، يُمكن إنشاء دوال الوصول في روبي بسطر واحد من التعليمات البرمجية عبر البرمجة الوصفية ؛ ومع ذلك، يُمكن أيضًا إنشاء دوال الوصول بالطريقة التقليدية في C++ وجافا. ولأن استدعاء هذه الدوال لا يتطلب استخدام الأقواس، فمن السهل تحويل متغير مثيل إلى دالة كاملة دون تعديل سطر واحد من التعليمات البرمجية المُستدعِية أو الحاجة إلى أي إعادة هيكلة، مما يُحقق وظائف مشابهة لخصائص C# و VB.NET .
تتشابه مُعرّفات الخصائص في بايثون مع مُعرّفات الخصائص في روبي، ولكنها تُؤدي إلى بعض التنازلات في عملية التطوير. فإذا بدأ المستخدم في بايثون باستخدام مُتغير مُتاح للعامة، ثم غيّر التنفيذ لاحقًا لاستخدام مُتغير خاص مُتاح عبر مُعرّف خاصية، فقد يحتاج الكود الداخلي للفئة إلى تعديل لاستخدام المُتغير الخاص بدلًا من الخاصية العامة. أما في روبي، فيُجبر تصميم روبي جميع مُتغيرات الكائنات على أن تكون خاصة، ولكنه يُوفر أيضًا طريقة سهلة لتعريف setالدوال get. ويتماشى هذا مع فكرة أنه في روبي، لا يتم الوصول مُباشرةً إلى الأعضاء الداخلية للفئة من خارجها؛ بل يتم إرسال رسالة إلى الفئة واستقبال رد.
جلسات تفاعلية
يمكن تشغيل الأمثلة التالية في غلاف Ruby مثل Interactive Ruby Shell ، أو حفظها في ملف وتشغيلها من سطر الأوامر عن طريق كتابة .ruby <filename>
مثال كلاسيكي لـ " مرحباً بالعالم" :
يكتب "مرحباً بالعالم!"بعض أكواد روبي الأساسية:
>> # كل شيء، بما في ذلك القيم الحرفية، هو كائن، لذا هذا يعمل: >> - 199 . abs => 199 >> 'ice is nice' . length => 11 >> 'ruby is cool.' . index ( 'u' ) => 1 >> "Nice Day Isn't It?" . downcase . split ( '' ) . uniq . sort . join => " '?acdeinsty"مدخل:
اطبع ' الرجاء كتابة الاسم >' الاسم = gets.chomp اطبع " مرحباً #{ الاسم } ."التحويلات:
puts 'أعطني رقمًا' number = gets . chomp puts number . to_i output_number = number . to_i + 1 puts output_number . to_s + ' هو رقم أكبر.'الأوتار
توجد طرق متنوعة لتعريف السلاسل النصية في لغة روبي.
المهام التالية متكافئة:
a = " \n هذه سلسلة نصية بين علامتي اقتباس مزدوجتين \n " a = %Q{ \n هذه سلسلة نصية بين علامتي اقتباس مزدوجتين \n } a = %{ \n هذه سلسلة نصية بين علامتي اقتباس مزدوجتين \n } a = %/\n هذه سلسلة نصية بين علامتي اقتباس مزدوجتين\n/ a = <<- BLOCKهذه سلسلة نصية محاطة بعلامات اقتباس مزدوجة BLOCKتدعم السلاسل النصية الاستيفاء المتغير :
فار = 3 . 14159 "بي هو #{ var } " => "بي هو 3.14159"المهام التالية متكافئة وتنتج سلاسل نصية خام :
a = 'هذه سلسلة نصية بين علامتي اقتباس مفردتين' a = %q{هذه سلسلة نصية بين علامتي اقتباس مفردتين}المجموعات
إنشاء واستخدام المصفوفة :
>> a = [ 3 , 'hello' , 14.5 , 1 , 2 , [ 6 , 15 ]] = > [3, "hello", 14.5, 1, 2, [6, 15]] >> a [ 2 ] = > 14.5 >> a . [] ( 2 ) = > 14.5 >> a.reverse => [[6, 15] , 2, 1, 14.5, "hello", 3] >> a.flatten.rotate = > ['hello', 14.5 , 1 , 2 , 6, 15, 3]إنشاء واستخدام مصفوفة ترابطية (تسمى في لغة روبي " هاش "):
>> hash = Hash.new # مكافئ لـ hash = {} >> hash = { water : ' wet' , fire : 'hot' } # يجعل السطر السابق زائداً عن الحاجة لأننا الآن >> # نُسند قيمة hash إلى كائن hash جديد ومنفصل >> puts hash [ :fire ] hot => nil >> ?> hash.each_pair do | key , value | # أو: hash.each do |key, value| ? > puts " # { key } is #{ value } " >> end water is wet fire is hot => {water: "wet", fire: "hot"} >> >> hash.delete : water # يحذف الزوج :water => 'wet' = > "wet" >> hash.delete_if { | key , value | value == ' hot' } # يحذف الزوج :fire => 'hot' => {}هياكل التحكم
عبارة شرطية:
# توليد عدد عشوائي وطباعة ما إذا كان زوجيًا أم فرديًا. إذا كان العدد زوجيًا ، فاطبع " إنه زوجي" . وإلا فاطبع " إنه فردي" .الكتل والمكررات
الصيغتان المستخدمتان لإنشاء كتلة برمجية:
{ puts 'Hello, World!' } # لاحظ الأقواس # أو: do puts 'Hello, World!' endيمكن تمرير كتلة برمجية إلى دالة كوسيط اختياري. العديد من الدوال المدمجة تحتوي على مثل هذه الوسائط:
File.open ( ' file.txt' , 'w' ) do | file | # 'w' تعني "وضع الكتابة" file.puts ' تمت كتابة بعض النصوص.' end # يتم إغلاق الملف تلقائيًا هناFile.readlines ( 'file.txt' ) . each do | line | puts line end # = > تم كتابة بعض النصوص.تمرير المعاملات إلى كتلة برمجية لتكون دالة مغلقة :
>> # في متغير مثيل كائن (يُشار إليه بـ '@')، قم بحفظ كتلة. ?> def remember ( & a_block ) ?> @block = a_block >> end >> => :remember >> >> # استدعاء الدالة السابقة، مع إعطائها كتلة تأخذ اسمًا. >> remember { | name | puts "Hello, #{ name } !" } => #<Proc:0x00007ff0b9823460 (irb):8> >> >> # استدعاء الإغلاق (لاحظ أن هذا لا يُغلق على أي متغيرات حرة): >> @block . call ( 'Jon' ) Hello, Jon! => nilإنشاء دالة مجهولة :
proc { | arg | puts arg } Proc.new { | arg | puts arg } lambda { | arg | puts arg } -> ( arg ) { puts arg } # تم تقديمه في Ruby 1.9إعادة الإغلاقات من دالة:
? > def create_set_and_get ( initial_value = 0 ) # لاحظ القيمة الافتراضية 0 ? > closure_value = initial_value ?> [ Proc.new { | x | closure_value = x } , Proc.new { closure_value } ] >> end >> >> setter , getter = create_set_and_get # تُرجع قيمتين >> setter.call ( 21 ) >> getter.call = > 21# يمكن أيضًا استخدام متغيرات المعاملات كرابط للإغلاق، # لذا يمكن إعادة كتابة ما سبق على النحو التالي:دالة إنشاء_تعيين_واسترجاع ( قيمة_الإغلاق = 0 ) [ إجراء { | س | قيمة_الإغلاق = س } ، إجراء { قيمة_الإغلاق } ] نهايةإخضاع تدفق التحكم في البرنامج لكتلة تم توفيرها في وقت الاستدعاء:
?> def use_hello ?> yield "hello" >> end >> >> # استدعاء الدالة السابقة، مع تمرير كتلة برمجية إليها. >> use_hello { | string | puts string } hello => nilالتكرار على التعدادات والمصفوفات باستخدام الكتل:
>> array = [ 1 , 'hi' , 3 . 14 ] >> array . each { | item | puts item } 1 hi 3.14 => [1, "hi", 3.14] >> >> array . each_index { | index | puts " #{ index } : #{ array [ index ] } " } 0: 1 1: hi 2: 3.14 => [1, "hi", 3.14] >> >> # يستخدم ما يلي نطاقًا (a..b) >> ( 3 .. 6 ) . each { | num | puts num } 3 4 5 6يمكن لدالة مثل هذه injectأن تقبل كلاً من مُعامل وكتلة برمجية. injectتقوم الدالة بالتكرار على كل عنصر من عناصر القائمة، وتُنفذ عليه وظيفة معينة مع الاحتفاظ بقيمة إجمالية. وهذا يُشابه الدالة foldlفي لغات البرمجة الوظيفية . على سبيل المثال:
>> [ 1 , 3 , 5 ]. inject ( 10 ) { | sum , element | sum + element } => 19في المرور الأول، يستقبل البرنامج 10 (الوسيط المُدخل) كـ sum1، و1 (العنصر الأول من المصفوفة) كـ element1. يُعيد هذا 11، والذي يُصبح 11 sumفي المرور التالي. يُضاف 11 إلى 3 للحصول على 14، والذي يُضاف بدوره إلى 5 في المرور الثالث، ليُعيد في النهاية 19.
استخدام التعداد والكتلة لتربيع الأرقام من 1 إلى 10 (باستخدام نطاق ):
>> ( 1 .. 10 ) . collect { | x | x * x } => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]أو استدعاء دالة على كل عنصر ( mapوهو مرادف لـ collect):
>> ( 1 .. 5 ) . map ( & :to_f ) => [1.0, 2.0, 3.0, 4.0, 5.0]الصفوف الدراسية
يُعرّف الكود التالي فئةً باسم Person. بالإضافة إلى initializeالمُنشئ المعتاد لإنشاء كائنات جديدة، تحتوي هذه الفئة على طريقتين: الأولى لتجاوز <=>عامل المقارنة (بحيث Array#sortيمكن فرز الكائنات حسب العمر)، والأخرى لتجاوز to_sطريقة (بحيث Kernel#putsيمكن تنسيق مُخرجاتها). فيما يلي attr_readerمثال على البرمجة الوصفية في روبي: attr_accessorتُعرّف هذه الفئة دوال الوصول والتعديل لمتغيرات النسخة، ولكنها attr_readerتُعرّف دوال الوصول فقط. آخر عبارة يتم تقييمها في الدالة هي قيمتها المُعادة، مما يسمح بحذف returnعبارة صريحة.
class Person attr_reader :name , :age def initialize ( name , age ) @name , @age = name , age end def <=> ( person ) # عامل المقارنة للفرز @age <=> person.age end def to_s " #{ @name } ( #{ @age } )" end endgroup = [ Person . new ( "Bob" , 33 ), Person . new ( "Chris" , 16 ), Person . new ( "Ash" , 23 ) ]puts group . sort . reverseيقوم الكود السابق بطباعة ثلاثة أسماء بترتيب عكسي حسب العمر:
بوب (33) آش (23) كريس (16) Personهو ثابت وهو مرجع إلى Classكائن.
صفوف مفتوحة
في لغة روبي، لا تُغلق الفئات أبدًا: يُمكن دائمًا إضافة توابع إلى فئة موجودة. ينطبق هذا على جميع الفئات، بما في ذلك الفئات القياسية المُدمجة. كل ما عليك فعله هو فتح تعريف فئة موجودة، وسيتم إضافة المحتوى الجديد المُحدد إلى المحتوى الحالي. إليك مثال بسيط لإضافة تابع جديد إلى Timeفئة من المكتبة القياسية:
>> # إعادة فتح فئة الوقت في روبي ?> class Time ?> def yesterday ?> self - 86400 ?> end >> end => :yesterday >> >> today = Time . now => 2025-08-20 10:34:33.595383429 +0900 >> yesterday = today . yesterday => 2025-08-19 10:34:33.595383429 +0900تُعرف إضافة الدوال إلى فئات مُعرّفة مسبقاً باسم "تعديل الكود" . وإذا تمّت هذه الممارسة بتهوّر، فقد تؤدي إلى تعارضات في السلوك مع نتائج غير متوقعة لاحقة، بالإضافة إلى مشاكل في قابلية توسيع الكود.
منذ إصدار Ruby 2.0 أصبح من الممكن استخدام التحسينات لتقليل العواقب السلبية المحتملة لتعديل التعليمات البرمجية، وذلك عن طريق حصر نطاق التعديل في مناطق معينة من قاعدة التعليمات البرمجية.
# إعادة فتح وحدة فئة الوقت في روبي RelativeTimeExtensions refine Time do def half_a_day_ago self - 43200 end end endوحدة MyModule فئة MyClass # السماح باستخدام التحسين باستخدام RelativeTimeExtensionsدالة نافذة الوقت . الآن . منذ نصف يوم نهاية نهاية نهايةالاستثناءات
يتم طرح استثناء عند raiseإجراء الاستدعاء:
يرفعيمكن إضافة رسالة اختيارية إلى الاستثناء:
ارفع "هذه رسالة"يمكن للمبرمج أيضاً تحديد الاستثناءات:
قم برفع خطأ ArgumentError ، "الوسائط غير قانونية!"بدلاً من ذلك، يمكن تمرير نسخة استثناء إلى raiseالطريقة:
raise ArgumentError.new ( " وسائط غير صالحة! " )يُعد هذا التركيب الأخير مفيدًا عند إنشاء نسخة من فئة استثناء مخصصة تحتوي على مُنشئ يأخذ أكثر من وسيط واحد:
class ParseError < Exception def initialize ( input , line , pos ) super "تعذر تحليل ' #{ input } ' في السطر #{ line } ، الموضع #{ pos } " end endraise ParseError.new ( " Foo " , 3 , 9 )تُعالج الاستثناءات بواسطة هذه rescueالعبارة. يمكن لهذه العبارة التقاط الاستثناءات التي ترث من StandardError. من الكلمات المفتاحية الأخرى للتحكم في التدفق التي يمكن استخدامها عند معالجة الاستثناءات : elseو ensure.
ابدأ نفّذ شيئًا ما، إنقاذ معالجة الاستثناء، وإلا افعل هذا إذا لم يتم طرح استثناء، تأكد افعل هذا سواء تم طرح استثناء أم لا، نهايةمن الأخطاء الشائعة محاولة معالجة جميع الاستثناءات باستخدام عبارة إنقاذ بسيطة. لمعالجة جميع الاستثناءات، يجب كتابة ما يلي:
بداية # قم بشيء ما إنقاذ استثناء # كود معالجة الاستثناء هنا. # لا تكتب "rescue" فقط؛ فهذا لا يلتقط سوى StandardError، وهو فئة فرعية من Exception. نهايةأو التقاط استثناءات محددة:
ابدأ # قم بشيء ما، إنقاذ خطأ وقت التشغيل # تعامل فقط مع خطأ وقت التشغيل وفئاته الفرعية ، نهايةمن الممكن أيضاً تحديد أن يكون كائن الاستثناء متاحاً لعبارة المعالج:
ابدأ # قم بشيء ما، إنقاذ خطأ وقت التشغيل => e # معالجة، قد تتضمن e، مثل "puts e.to_s" نهايةبدلاً من ذلك، يتم تخزين الاستثناء الأخير في المتغير العام السحري $!.
ويمكن أيضاً رصد العديد من الاستثناءات:
ابدأ # قم بشيء ما، إنقاذ خطأ وقت التشغيل ، مهلة :: خطأ => e # معالجة، ربما تتضمن e نهايةالبرمجة الوصفية
يُمكن لبرامج روبي تعديل جوانب من بنيتها برمجياً أثناء التشغيل ، وهي جوانب ثابتة في لغات البرمجة الأكثر جموداً، مثل تعريفات الأصناف والأساليب. يُمكن استخدام هذا النوع من البرمجة الوصفية لكتابة كود أكثر اختصاراً وتوسيع نطاق اللغة بشكل فعّال.
على سبيل المثال، يقوم كود روبي التالي بإنشاء دوال جديدة للفئة المدمجة String، بناءً على قائمة ألوان. تقوم هذه الدوال بتغليف محتوى السلسلة النصية بعلامة HTML مُنسقة باللون المُناسب.
COLORS = { أسود : "000" ، أحمر : "f00" ، أخضر : "0f0" ، أصفر : "ff0" ، أزرق : "00f" ، أرجواني : "f0f" ، سماوي : "0ff" ، أبيض : "fff" }class String COLORS.each do | color , code | define_method "in_ # { color } " do "<span style= " color: ## { code } " > #{ self } </span> " end end endويمكن استخدام الطرق المُولَّدة على النحو التالي:
>> "مرحباً بالعالم!" . in_blue => "<span style="color: #00f">مرحباً بالعالم!</span>"لتنفيذ ما يعادل ذلك في العديد من اللغات الأخرى، سيتعين على المبرمج كتابة كل طريقة ( in_black، in_red، in_green، إلخ.) بشكل منفصل.
تتضمن بعض الاستخدامات الأخرى المحتملة لبرمجة ما وراء اللغة في روبي ما يلي:
- اعتراض وتعديل استدعاءات الأساليب
- تطبيق نماذج الوراثة الجديدة
- إنشاء فئات ديناميكيًا من المعلمات
- التسلسل التلقائي للكائنات
- المساعدة التفاعلية وتصحيح الأخطاء
مراجع
- ↑ " [ ruby-talk:01120 ] رد: قيمة while ..."
في بناء جملة Ruby، فإن العبارة هي مجرد حالة خاصة من التعبير الذي لا يمكن أن يظهر كوسيط (على سبيل المثال، التعيين المتعدد).
- ↑ " [ ruby-talk:02460 ] ردًا على: سؤال الأسبقية" .
لا يمكن أن يكون البيان [...] جزءًا من التعبير إلا إذا تم تجميعه بين قوسين.
- بناء جملة لغة البرمجة
