الفرق بين المراجعتين لصفحة: «Ruby/methods»

من موسوعة حسوب
لا ملخص تعديل
ط مراجعة وتدقيق.
 
سطر 1: سطر 1:
=التوابع=
<noinclude>{{DISPLAYTITLE: التوابع في روبي}}</noinclude>
التوابع في لغة روبي تتضمّن الوظائف التي يقوم بها برنامجك. إليك هذا المثال لتعريف تابع بسيط:<syntaxhighlight lang="ruby">
تتضمّن التوابع في لغة روبي الوظائف التي يقوم بها برنامجك. إليك هذا المثال لتعريف تابع بسيط:<syntaxhighlight lang="ruby">
def one_plus_one
def one_plus_one
 1 + 1
 1 + 1
end 
end 
</syntaxhighlight>تعريف التابع يتكوّن من الكلمة المحجوزة def يتبعها اسم التابع، ثمّ جسم التابع، فالقيمة المعادة وفي النهاية الكلمة المحجوزة end. فعند تنفيذ التابع في المثال  السابق ستُرجع القيمة 2. هذا القسم سيغطّي تعريف التّوابع. ارجع إلى توصيف استدعاء التوابع لتتعرف على الصيغ المستخدمة لذلك.
</syntaxhighlight>تعريف التابع يتكوّن من الكلمة المحجوزة <code>def</code> يتبعها اسم التابع، ثمّ جسم التابع، فالقيمة المعادة وفي النهاية الكلمة المحجوزة <code>end</code>. فعند تنفيذ التابع في المثال السابق، ستُعاد القيمة 2. هذا القسم سيغطّي تعريف التّوابع. ارجع إلى توثيق [[Ruby/calling methods|استدعاء التوابع]] لتتعرف على الصيغ المستخدمة لذلك الغرض.
==تسمية التوابع==
==تسمية التوابع==
يمكن أن تستخدم لاسم التابع أحد المعاملات، وإلا فعليك أن تبتدئه بحرف أبجديّ أو أيّ محرف من محارف لوحة المفاتيح (أيضًا تعرف باسم محارف البتات الثمانية). ويمكن للاسم أن يتضمن أحرفًا وأرقامًا وشرطة سفليّة أو أيّ محرف من محارف البتات الثمانية. ومن المعتاد أن تستخدم الشرطة السفليّة لتفصل بين الكلمات في أسماء التوابع التي تتضمن كلمات عدّة.<syntaxhighlight lang="ruby">
يمكن أن تستخدم لاسم التابع أحد المعاملات، وإلا فعليك أن تبتدئه بحرف أبجديّ أو أيّ محرف من محارف لوحة المفاتيح (أيضًا تعرف باسم محارف البتات الثمانية أي كل محرف بحجم 8 بت). ويمكن للاسم أن يتضمن أحرفًا وأرقامًا وشرطة سفليّة (_)، أو أيّ محرف من محارف البتات الثمانية. ومن المعتاد أن تستخدم الشرطة السفليّة لتفصل بين الكلمات في أسماء التوابع التي تتضمن كلمات عدّة.<syntaxhighlight lang="ruby">
def method_name
def method_name
 puts "use underscores to separate words"
 puts "use underscores to separate words"
end
end
</syntaxhighlight>يجب أن تكتب البرامج بلغة روبي باستخدام مجموعات محارف متوافقة مع مجموعة المحارف US-ASCII مثل UTF-8 و ISO-8859-1. فإذا كان البتات الثمانية مضبوطة في مجموعات المحارف هذه، فهذا يدل على أنّ المحرف هو من المحارف الموسّعة، ولغة روبي تسمح أن تحتوي أسماء التوابع والمعرّفات الأخرى على تلك المحارف. إلا أنّ لغة روبي لا تسمح باستخدام بعض المحارف مثل ASCII NUL الذي رمزه ‎\x00.
</syntaxhighlight>يجب أن تكتب البرامج بلغة روبي باستخدام مجموعات محارف متوافقة مع مجموعة المحارف [[Arduino/asciichart|US-ASCII]] مثل UTF-8 و ISO-8859-1. فإذا كان البتات الثمانية مضبوطة في مجموعات المحارف هذه، فهذا يدل على أنّ المحرف هو من المحارف الموسّعة، ولغة روبي تسمح أن تحتوي أسماء التوابع والمعرّفات الأخرى على تلك المحارف. إلا أنّ لغة روبي لا تسمح باستخدام بعض المحارف مثل [[Arduino/asciichart|ASCII NUL]] الذي رمزه ‎\x00.


إليك بعض الأمثلة عن التوابع التي تصلح تسميتها في لغة روبي:<syntaxhighlight lang="ruby">
إليك بعض الأمثلة عن التوابع التي تصلح تسميتها في لغة روبي:<syntaxhighlight lang="ruby">
سطر 19: سطر 19:
 puts "means hello in Japanese"
 puts "means hello in Japanese"
end
end
</syntaxhighlight>وعادة ما تكون أسماء التوابع متوافقة مع نظام US-ASCII كون الحروف الخاصة به متوفرة على جميع لوحات المفاتيح. ويمكن لأسماء التوابع أن تنتهي بعلامة التعجّب ! أو علامة الاستفهام ? أو علامة المساواة = .
</syntaxhighlight>وعادة ما تكون أسماء التوابع متوافقة مع نظام [[Arduino/asciichart|US-ASCII]] كون الحروف الخاصة به متوفرة على جميع لوحات المفاتيح. ويمكن لأسماء التوابع أن تنتهي بعلامة التعجّب <code>!</code> أو علامة الاستفهام <code>?</code> أو علامة المساواة <code>=</code>.


إن التوابع المنتهية بعلامة تعجب تستدعى وتُنفّذ مثل أيّ تابع آخر، إلّا أنّها عادة ما تصنّف كتوابع خطرة. ففي مكتبة نواة لغة روبي يُعدّ التّابع خطيرًا إذا كان يغيّر من قيمة المتغيّر الذي يستقبله، ولذلك يُميّز بعلامة التعجّب في آخره.
إن التوابع المنتهية بعلامة تعجب تستدعى وتُنفّذ مثل أيّ تابع آخر، إلّا أنّها عادة ما تصنّف كتوابع خطرة. ففي مكتبة نواة لغة روبي يُعدّ التّابع خطيرًا إذا كان يغيّر من قيمة المتغيّر الذي يستقبله، ولذلك يُميّز بعلامة التعجّب في آخره.
سطر 25: سطر 25:
وفي هذه المكتبة يوجد لكلّ تابع من هذا النّوع تابعًا آخر مقابلًا ليس خطيرًا أي أنّه لا يغيّر من قيمة المتغيّر الذي يستقبله، وهذه التّوابع يكون لها نفس التسمية إلا أنّها لا تنتهي بإشارة التّعجب.
وفي هذه المكتبة يوجد لكلّ تابع من هذا النّوع تابعًا آخر مقابلًا ليس خطيرًا أي أنّه لا يغيّر من قيمة المتغيّر الذي يستقبله، وهذه التّوابع يكون لها نفس التسمية إلا أنّها لا تنتهي بإشارة التّعجب.


أمّا المتعارف عليه بالنّسبة للتوابع التي تنتهي تسميتها بإشارة استفهام فهي التوابع التي تُرجع قيمة منطقيّة، لكنّها ليست بالضّرورة تعيد true أو false، بل غالبًا ما تعيد كائنًا يعبّر عن true أو قيمة الإيجاب.
أمّا المتعارف عليه بالنّسبة للتوابع التي تنتهي تسميتها بإشارة استفهام فهي التوابع التي تُرجع قيمة منطقيّة، لكنّها لا تعيد بالضّرورة القيمة <code>true</code> أو <code>false</code>، بل غالبًا ما تعيد كائنًا يعبّر عن <code>true</code> أو قيمة الإيجاب.


والتوابع التي تنتهي بإشارة مساواة فهي توابع الإسناد، وبالنسبة لهذا النوع من التوابع تُتجاهل القيمة المعادة وتُرجع معاملات التابع بدلًا منها.
والتوابع التي تنتهي بإشارة مساواة فهي توابع الإسناد؛ وبالنسبة لهذا النوع من التوابع، تُتجاهل القيمة المعادة وتُرجع معاملات التابع بدلًا منها.


فيما يلي أسماء التوابع المعبرة عن مختلف العمليات في لغة روبي، كلّ واحدة من هذه العمليات تقبل معاملًا واحدًا فقط. تجد بعد رمز العملية الاستخدام الشهير لها أو اسم العملية. لاحظ أنّك إن غيّرت ما تقوم به كلّ عمليّة فستسبّب لبسًا لدى المستخدم، إذ أنّ المتوقّع من إشارة الجمع أن تجمع، ومن إشارة الطرح أن تطرح، وهكذا. أضف إلى ذلك أنّك لن تتمكّن من تغيير أولويّة أيّ من هذه العمليات. <syntaxhighlight lang="text">
فيما يلي أسماء التوابع المعبرة عن مختلف العمليات في لغة روبي، كلّ واحدة من هذه العمليات تقبل معاملًا واحدًا فقط. تجد بعد رمز العملية الاستخدام الشهير لها أو اسم العملية. لاحظ أنّك إن غيّرت ما تقوم به كلّ عمليّة فستسبّب لبسًا لدى المستخدم، إذ أنّ المتوقّع من إشارة الجمع أن تجمع، ومن إشارة الطرح أن تطرح، وهكذا. أضف إلى ذلك أنّك لن تتمكّن من تغيير أولويّة أيّ من هذه العمليات. 
+
{| class="wikitable"
جمع
!المعامل
 
!العملية
-
|-
طرح
|<nowiki>+</nowiki>
 
|جمع
*
|-
ضرب
|<nowiki>-</nowiki>
 
|طرح
**
|-
قوة
|*
 
|ضرب
/
|-
قسمة
|**
 
|قوة
%
|-
باقي القسمة، أو سلسلة %
|/
 
|قسمة
&
|-
AND
|%
 
|باقي القسمة، أو سلسلة %
^
|-
OR الحصرية
|&
 
|العملية AND
>>
|-
إزاحة لليمين
|^
 
|العملية XOR
<<
|-
إزاحة لليسار، أو إضافة
|>>
 
|إزاحة لليمين
==
|-
اختبار المساواة
|<<
 
|إزاحة لليسار، أو إضافة
!=
|-
اختبار عدم المساواة
|==
 
|اختبار المساواة
===
|-
المساواة التامة
|=!
 
|اختبار عدم المساواة
=~
|-
مطابقة النمط (ليس خاصًّا بالتعبيرات النظامية فحسب)
|===
 
|المساواة التامة
!~
|-
عدم مطابقة النمط
|~=
 
|مطابقة النمط (ليس خاصًّا بالتعبيرات النظامية فحسب)
<=>
|-
المقارنة والمعروف أيضًا بمعامل سفينة الفضاء
|~!
 
|عدم مطابقة النمط
<
|-
أصغر من
|<=>
 
|المقارنة والمعروف أيضًا بمعامل سفينة الفضاء
<=
|-
أصغر من أو يساوي
|>
 
|أصغر من
>
|-
أكبر من
|=>
 
|أصغر من أو يساوي
>=
|-
أكبر من أو يساوي
|<
</syntaxhighlight>لأجل تعريف توابع أحادية تغيّر سلوك إشارة الجمع والطرح والضرب والنفي المنطقي، عليك أن تُتبع رمز العملية بالرمز @ مثل: ‎+@‎ أو ‎!@‎ كما في المثال التالي:<syntaxhighlight lang="ruby">
|أكبر من
|-
|=<
|أكبر من أو يساوي
|}
لأجل تعريف توابع أحادية تغيّر سلوك إشارة الجمع والطرح والضرب والنفي المنطقي، عليك أن تُتبع رمز العملية بالرمز <code>@</code> مثل: ‎<code>+@</code>‎ أو ‎<code>!@‎</code> كما في المثال التالي:<syntaxhighlight lang="ruby">
class C
class C
 def -@
 def -@
سطر 97: سطر 102:
obj = C.new
obj = C.new
-obj # "you inverted this object" يطبع
-obj # "you inverted this object" يطبع
</syntaxhighlight>التوابع الأحادية لا تقبل أي معاملات. بالإضافة لذلك يمكن تعريف التوابع التي تستخدم للإشارة إلى العناصر وإسناد قيمٍ إليها بالشّكل [] أو ‎[]=‎ على التوالي وبالترتيب. وكلاهما بالإمكان أن يأخذ معاملًا واحدًا أو أكثر. ويمكن لتابع الإشارة للعناصر ألا يأخذ أيّ معامل. <syntaxhighlight lang="ruby">
</syntaxhighlight>التوابع الأحادية لا تقبل أي معاملات. بالإضافة لذلك يمكن تعريف التوابع التي تستخدم للإشارة إلى العناصر وإسناد قيمٍ إليها بالشّكل <code>[]</code> أو <code>‎[]=</code>‎ على التوالي وبالترتيب. وكلاهما بالإمكان أن يأخذ معاملًا واحدًا أو أكثر. ويمكن لتابع الإشارة للعناصر ألا يأخذ أيّ معامل. <syntaxhighlight lang="ruby">
class C
class C
 def [](a, b)
 def [](a, b)
سطر 111: سطر 116:
</syntaxhighlight>
</syntaxhighlight>
==القيم المعادة==
==القيم المعادة==
تُعيد التوابع بشكل افتراضيّ آخر تعبير برمجيّ يصل إليه التنفيذ في جسم التابع، ففي المثال أعلاه، فالتعبير الأخير (والوحيد) الذي نُفّذ كان عمليّة جمع بسيطة 1+1. ويمكن أيضًا استخدام الكلمة المحجوزة return للتأكيد بأنّ التابع يعيد قيمة.<syntaxhighlight lang="ruby">
تُعيد التوابع بشكل افتراضيّ آخر تعبير برمجيّ يصل إليه التنفيذ في جسم التابع؛ في المثال أعلاه، التعبير الأخير (والوحيد) الذي نُفّذ كان عمليّة جمع بسيطة 1+1. ويمكن أيضًا استخدام الكلمة المحجوزة <code>return</code> للتأكيد بأنّ يعيد التابع القيمة التي تليها.<syntaxhighlight lang="ruby">
def one_plus_one
def one_plus_one
 return 1 + 1
 return 1 + 1
end
end
</syntaxhighlight>كما يمكن استخدام كلمة return لإنهاء تنفيذ التابع دون إكمال التعبيرات البرمجيّة التي تليها.<syntaxhighlight lang="ruby">
</syntaxhighlight>كما يمكن استخدام كلمة <code>return</code> لإنهاء تنفيذ التابع دون إكمال التعبيرات البرمجيّة التي تليها.<syntaxhighlight lang="ruby">
def two_plus_two
def two_plus_two
 return 2 + 2
 return 2 + 2
 1 + 1  # لا يتمّ تنفيذ هذا السطر أبدًا
 1 + 1  # لا يتمّ تنفيذ هذا السطر أبدًا
end
end
</syntaxhighlight>لاحظ أنّه - كما أشرنا سابقًا - في حالة توابع الإسناد فإنّ القيمة المعادة تُتجاهل ويعيد التابع بدلًا منها المعامل الذي مُرّر إليه:<syntaxhighlight lang="ruby">
</syntaxhighlight>لاحظ أنّه - كما أشرنا سابقًا - في حالة توابع الإسناد، فإنّ القيمة المعادة تُتجاهل ويعيد التابع بدلًا منها المعامل الذي مُرّر إليه:<syntaxhighlight lang="ruby">
def a=(value)
def a=(value)
 return 1 + value
 return 1 + value
سطر 133: سطر 138:
 # ...
 # ...
end
end
</syntaxhighlight>وبهذه الطريقة تضيف تابعًا إلى صنف class. كما يمكنك تعريف تابع لأغراض صنف معين وذلك بإضافة كلمة class:<syntaxhighlight lang="ruby">
</syntaxhighlight>وبهذه الطريقة تضيف تابعًا إلى صنف (class). كما يمكنك تعريف تابع لأغراض صنف معين وذلك بإضافة كلمة class:<syntaxhighlight lang="ruby">
class C
class C
 def my_method
 def my_method
سطر 145: سطر 150:
 end
 end
end
end
</syntaxhighlight>وهذه الطريقة تُعد حالة خاصة من إحدى قواعد الصيغة في لغة روبي، وهي القدرة على إضافة تابع لأيّ كائن، وبما أنّ الأصناف بحدّ ذاتها هي نوع من الكائنات فبالإمكان ببساطة إضافة تابع إلى كائن الصنف
</syntaxhighlight>وهذه الطريقة تُعد حالة خاصة من إحدى قواعد الصيغة في لغة روبي، وهي القدرة على إضافة تابع لأيّ كائن. وبما أنّ الأصناف بحدّ ذاتها هي نوع من الكائنات، فبالإمكان ببساطة إضافة تابع إلى كائن الصنف


وفيما يلي صيغة إضافة تابع إلى كائن ما:<syntaxhighlight lang="ruby">
وفيما يلي صيغة إضافة تابع إلى كائن ما:<syntaxhighlight lang="ruby">
سطر 153: سطر 158:
end
end
greeting.broaden # تعيد "Hello, world!"
greeting.broaden # تعيد "Hello, world!"
</syntaxhighlight>كلمة self هي كلمة محجوزة في اللغة تشير إلى الغرض الحالي من وجهة نظر مفسّر اللغة، فهي تسهّل تعريف تابع الصنف في المثال السابق.<syntaxhighlight lang="ruby">
</syntaxhighlight>كلمة <code>self</code> هي كلمة محجوزة في اللغة تشير إلى الغرض الحالي من وجهة نظر مفسّر اللغة، فهي تسهّل تعريف تابع الصنف في المثال السابق.<syntaxhighlight lang="ruby">
def String.hello
def String.hello
 "Hello, world!"
 "Hello, world!"
end
end
</syntaxhighlight>تعريف التابع بهذا الشكل يسمى "التابع المنفرد singleton method". فالتابع broaden في المثال السابق موجود في الكائن greeting فحسب، ولن تجده في أيّ متغيّر آخر من نوع السلسلة النصية string.
</syntaxhighlight>تعريف التابع بهذا الشكل يسمى "التابع المنفرد" (singleton method). فالتابع <code>broaden</code> في المثال السابق موجود في الكائن <code>greeting</code> فحسب، ولن تجده في أيّ متغيّر آخر من نوع السلسلة النصية <code>string</code>.
==إعادة التعريف==
==إعادة التعريف==
عندما يصادف مفسّر لغة روبي كلمة def قبل اسم تابع معرّف مسبقًا فإنّه لا يعدّ ذلك خطأ وإنّما يعيد تعريف هذا التابع. وهذا ما يسمّى بإعادة التعريف أو Overriding. إلّا أنّ هذه الإمكانيّة في لغة روبي تُعدّ خطرة ولا يستحسن استخدامها بشكل متكّرر، إلا في حالة توسيع أصناف اللغة الأساسية (core classes)، لأنّها قد تؤدي إلى نتائج غير معروفة. خذ على سبيل المثال تسلسل الأوامر التالي:<syntaxhighlight lang="text">
عندما يصادف مفسّر لغة روبي كلمة <code>def</code> قبل اسم تابع معرّف مسبقًا فإنّه لا يعدّ ذلك خطأ وإنّما يعيد تعريف هذا التابع. وهذا ما يسمّى بإعادة التعريف (Overriding). إلّا أنّ هذه الإمكانيّة في لغة روبي تُعدّ خطرة ولا يستحسن استخدامها بشكل متكّرر، إلا في حالة توسيع أصناف اللغة الأساسية (core classes)، لأنّها قد تؤدي إلى نتائج غير معروفة. خذ على سبيل المثال تسلسل الأوامر التالي:<syntaxhighlight lang="text">
>> "43".to_i
>> "43".to_i
=> 43
=> 43
سطر 170: سطر 175:
>> "43".to_i
>> "43".to_i
=> 42
=> 42
</syntaxhighlight>هذا سيسبب بكلّ تأكيد تخريبًا لأيّ شيفرة تستخدم التابع to_i من الصنف String الذي يحوّل سلسلة المحارف إلى أرقام.
</syntaxhighlight>هذا سيسبب بكلّ تأكيد تخريبًا لأيّ شيفرة تستخدم التابع <code>to_i</code> من الصنف <code>String</code> لاستخلاص أعدادٍ من سلسلة نصية.
==معاملات التوابع==
==وسائط التوابع==
يمكن للتابع أن يقبل معاملات وتكون مكتوبة على التتالي بعد اسم التابع:<syntaxhighlight lang="ruby">
يمكن للتابع أن يقبل وسائط وتكون مكتوبة على التتالي بعد اسم التابع:<syntaxhighlight lang="ruby">
def add_one(value)
def add_one(value)
 value + 1
 value + 1
end
end
</syntaxhighlight>عند استدعاء التابع add_one يجب على المستخدم أن يمرّر له معاملًا، وهذا المعامل هو متغيّر محليّ ضمن جسم التابع. ففي المثال السابق يضيف التابع واحدًا إلى هذا المعامل الذي مُرّر إليه، ويُعيد الناتج. فإذا أُعطي التابع 1 سيعيد 2.
</syntaxhighlight>عند استدعاء التابع <code>add_one</code>، يجب على المستخدم أن يمرّر له وسيطًا، وهذا الوسيط هو متغيّر محليّ ضمن جسم التابع. ففي المثال السابق، يضيف التابع واحدًا إلى هذا الوسيط الذي مُرّر إليه، ويُعيد الناتج. فإذا أُعطي التابع 1 سيعيد 2.


والأقواس المحيطة بالمعاملات اختيارية ويمكن حذفها:<syntaxhighlight lang="ruby">
والأقواس المحيطة بالوسائط اختيارية ويمكن حذفها:<syntaxhighlight lang="ruby">
def add_one value
def add_one value
 value + 1
 value + 1
end
end
</syntaxhighlight>وإذا كان لديك أكثر من معامل فافصل بينها بفواصل:<syntaxhighlight lang="ruby">
</syntaxhighlight>وإذا كان لديك أكثر من وسيط، فافصل بينها بفواصل:<syntaxhighlight lang="ruby">
def add_values(a, b)
def add_values(a, b)
 a + b
 a + b
end
end
</syntaxhighlight>فعند الاستدعاء يجب تمرير المعاملات بنفس الترتيب، وبكلمات أخرى يمكن القول أنّ المعاملات حساسة للترتيب.
</syntaxhighlight>فعند الاستدعاء، يجب تمرير الوسائط بنفس الترتيب؛ بعيارة أخرى، يمكن القول أنّ الوسائط حساسة للترتيب.
==القيم الافتراضية==
==القيم الافتراضية==
يمكن أن تحصل المعاملات على قيم افتراضية:<syntaxhighlight lang="ruby">
يمكن أن تحصل الوسائط على قيم افتراضية:<syntaxhighlight lang="ruby">
def add_values(a, b = 1)
def add_values(a, b = 1)
 a + b
 a + b
end
end
</syntaxhighlight>ولا يشترط أن تكون القيمة الافتراضية في بداية أو نهاية المعاملات، إلّا أن المعاملات ذات القيم الافتراضية يجب أن تجمّع معًا، فالمثال التالي مقبول:<syntaxhighlight lang="ruby">
</syntaxhighlight>ولا يشترط أن تكون القيمة الافتراضية في بداية أو نهاية الوسائط، إلّا أن الوسائط ذات القيم الافتراضية يجب أن تجمّع معًا، فالمثال التالي مقبول:<syntaxhighlight lang="ruby">
def add_values(a = 1, b = 2, c)
def add_values(a = 1, b = 2, c)
 a + b + c
 a + b + c
end
end
</syntaxhighlight>أما هذا المثال فسيعطي خطأ في الصيغة SyntaxError<syntaxhighlight lang="ruby">
</syntaxhighlight>أما هذا المثال، فسيعطي الخطأ <code>[[Ruby/SyntaxError|SyntaxError]]</code>:<syntaxhighlight lang="ruby">
def add_values(a = 1, b, c = 1)
def add_values(a = 1, b, c = 1)
 a + b + c
 a + b + c
end
end
</syntaxhighlight>
</syntaxhighlight>
 
==تفكيك المصفوفة==
== تفكيك المصفوفة ==
يمكنك تفكيك مصفوفة (أوس استخراج القيم منها) باستخدام أقواس مضاعفة في معاملات التابع:<syntaxhighlight lang="ruby">
يمكنك تفكيك مصفوفة (أوس استخراج القيم منها) باستخدام أقواس مضاعفة في معاملات التابع:<syntaxhighlight lang="ruby">
def my_method((a, b))
def my_method((a, b))
سطر 210: سطر 214:
</syntaxhighlight>هذا المثال يطبع:<syntaxhighlight lang="text">
</syntaxhighlight>هذا المثال يطبع:<syntaxhighlight lang="text">
{:a=>1, :b=>2} 
{:a=>1, :b=>2} 
</syntaxhighlight>ويُتجاهل كلّ عنصر في المصفوفة زائد على عدد المعاملات.<syntaxhighlight lang="ruby">
</syntaxhighlight>ويُتجاهل كلّ عنصر في المصفوفة زائد على عدد الوسائط.<syntaxhighlight lang="ruby">
def my_method((a, b))
def my_method((a, b))
 p a: a, b: b
 p a: a, b: b
سطر 217: سطر 221:
</syntaxhighlight>وهذا المثال له نفس نتيجة المثال السابق.
</syntaxhighlight>وهذا المثال له نفس نتيجة المثال السابق.


يمكنك استخدام الرمز * لتحصيل المعاملات المتبقية أيًا كان عددها في المصفوفة، فالمثال التالي يفصل المصفوفة فيسند أول عنصر منها في المعامل الأول، والباقي يسند كمصفوفة في المعامل الثاني:<syntaxhighlight lang="ruby">
يمكنك استخدام الرمز <code>*</code> لتحصيل الوسائط المتبقية أيًا كان عددها في المصفوفة؛ فالمثال التالي يفصل المصفوفة ليسند أول عنصر منها في الوسيط الأول، والباقي يسنده كمصفوفة إلى الوسيط الثاني:<syntaxhighlight lang="ruby">
def my_method((a, *b))
def my_method((a, *b))
 p a: a, b: b
 p a: a, b: b
سطر 224: سطر 228:
</syntaxhighlight>هذا المثال يطبع:<syntaxhighlight lang="text">
</syntaxhighlight>هذا المثال يطبع:<syntaxhighlight lang="text">
{:a=>1, :b=>[2, 3]}
{:a=>1, :b=>[2, 3]}
</syntaxhighlight>أيّ معامل يستجيب للتابع to_ary يمكن استخدامه في عملية التفكيك هذه، فإذا كان لديك كائن آخر تريد أن تفكّكه بنفس الطريقة فعليك أن تعرّف له تابع to_ary الخاص به.
</syntaxhighlight>أيّ وسيط يستجيب للتابع <code>to_ary</code> يمكن استخدامه في عملية التفكيك هذه. فإذا كان لديك كائن آخر تريد أن تفكّكه بنفس الطريقة، فعليك أن تعرّف له التابع <code>to_ary</code> الخاص به.


يمكنك استخدام أقواس ضمنية لتفكيك مصفوفة مُرّرت كأحد المعاملات، لكن إذا لم يكن المعامل المقابل له من نوع مصفوفة Array فسوف يُسند هذا المعامل إلى المعامل الأول ضمن قوسي التفكيك، بينما تأخذ بقية المعاملات قيمة nil:<syntaxhighlight lang="ruby">
يمكنك استخدام أقواس ضمنية لتفكيك مصفوفة مُرّرت كوسيط، لكن إذا لم يكن الوسيط المقابل له من نوع [[Ruby/Array|مصفوفة]]، فسوف يُسند هذا الوسيط إلى الوسيط الأول ضمن قوسي التفكيك، بينما تأخذ بقية الوسائط القيمة <code>nil</code>:<syntaxhighlight lang="ruby">
def my_method(a, (b, c), d)
def my_method(a, (b, c), d)
 p a: a, b: b, c: c, d: d
 p a: a, b: b, c: c, d: d
سطر 238: سطر 242:
end
end
</syntaxhighlight>
</syntaxhighlight>
==معاملات المصفوفة \ المصنّف==
==الوسائط التي من النوع: مصفوفة وجدول Hash==
إضافة الرمز * في بداية اسم المعامل يسبب تحويل جميع المعاملات الإضافية إلى مصفوفة:<syntaxhighlight lang="ruby">
إضافة الرمز <code>*</code> في بداية اسم الوسيط يسبب تحويل جميع الوسائط الإضافية إلى مصفوفة:<syntaxhighlight lang="ruby">
def gather_arguments(*arguments)
def gather_arguments(*arguments)
 p arguments
 p arguments
end
end
gather_arguments 1, 2, 3 # [1, 2, 3] تطبع
gather_arguments 1, 2, 3 # [1, 2, 3] تطبع
</syntaxhighlight>ويجب أن يأتي هذا المعامل في آخر المعاملات الموضعية وعليه أن يسبق أيّ معامل قيم مفتاحيّة.
</syntaxhighlight>ويجب أن يأتي هذا الوسيط في آخر الوسائط الموضعية وعليه أن يسبق أيّ وسيط مسمى.


كما يمكن للمصفوفة الناتجة أن تتضمّن مصنِّفًا في نهايتها إذا مُرّر هذا المصنّف عند الاستدعاء بعد جميع المعاملات الموضعي. <syntaxhighlight lang="ruby">
كما يمكن للمصفوفة الناتجة أن تتضمّن [[Ruby/Hash|جدول Hash]] في نهايتها إذا مُرّر هذا النوع عند الاستدعاء بعد جميع الوسائط الموضعية. <syntaxhighlight lang="ruby">
gather_arguments 1, a: 2 # [1, {:a=>2}] تطبع
gather_arguments 1, a: 2 # [1, {:a=>2}] تطبع
</syntaxhighlight>إلّا أنّ هذه الحالة تحصل فقط عندما لا يعرّف التابع أيّ معاملات من نوع القيم المفتاحية.<syntaxhighlight lang="ruby">
</syntaxhighlight>إلّا أنّ هذه الحالة تحصل فقط عندما لا يعرّف التابع أيّ وسائط من نوع "الوسائط المسماة".<syntaxhighlight lang="ruby">
def gather_arguments_keyword(*positional, keyword: nil)
def gather_arguments_keyword(*positional, keyword: nil)
p positional: positional, keyword: keyword
p positional: positional, keyword: keyword
سطر 254: سطر 258:
gather_arguments_keyword 1, 2, three: 3
gather_arguments_keyword 1, 2, three: 3
#=> unknown keyword: three (ArgumentError):تسبب ظهور خطأ
#=> unknown keyword: three (ArgumentError):تسبب ظهور خطأ
لاحظ أيضًا أنّ استخدام الرمز * وحده يسبب تجاهل أيّ معاملات.
# لاحظ أيضًا أنّ استخدام الرمز * وحده يسبب تجاهل أيّ معاملات.
def ignore_arguments(*)
def ignore_arguments(*)
end
end
</syntaxhighlight>
</syntaxhighlight>
==معاملات القيم المفتاحية==
==الوسائط المسماة==
معاملات القيم المفتاحية تشبه في آلية عملها المعاملات الموضعية ذات القيم الافتراضية:<syntaxhighlight lang="ruby">
الوسائط المسماة تشبه في آلية عملها الوسائط الموضعية ذات القيم الافتراضية:<syntaxhighlight lang="ruby">
def add_values(first: 1, second: 2)
def add_values(first: 1, second: 2)
 first + second
 first + second
end
end
</syntaxhighlight>يمكن قبول أيّ عدد من معاملات القيم المفتاحية باستخدام الرمز ** قبل اسم المعامل:<syntaxhighlight lang="ruby">
</syntaxhighlight>يمكن قبول أيّ عدد من الوسائط المسماة باستخدام الرمز <code>**</code> قبل اسم الوسيط:<syntaxhighlight lang="ruby">
def gather_arguments(first: nil, **rest)
def gather_arguments(first: nil, **rest)
 p first, rest
 p first, rest
سطر 269: سطر 273:
gather_arguments first: 1, second: 2, third: 3
gather_arguments first: 1, second: 2, third: 3
# {:second=>2, :third=>3} تطبع 1 ثم
# {:second=>2, :third=>3} تطبع 1 ثم
</syntaxhighlight>عند استدعاء تابع باستخدام القيم المفتاحية فمكن لها أن تأتي ضمن أيّ ترتيب، إلّا أنّ المعاملات غير المعرفة مسبقًا ستسبب ظهور خطأ من نوع ArgumentError
</syntaxhighlight>عند استدعاء تابع مع وسائط مسماة، فمن الممكن لها أن تأتي ضمن أيّ ترتيب، إلّا أنّ الوسائط غير المعرفة مسبقًا ستسبب ظهور خطأ من النوع <code>[[Ruby/ArgumentError|ArgumentError]]</code>.


وفي حال رغبتك باستخدام معاملات قيم مفتاحية مع معاملات موضعية فعليك أن تكتب جميع المعاملات الموضعية قبل أيّ معامل قيمة مفتاحية.
وفي حال رغبتك باستخدام وسائط مسماة مع وسائط موضعية، فعليك أن تكتب جميع الوسائط الموضعية قبل أيّ وسيط مسمى.
==معاملات الكتلة البرمجية==
==وسائط الكتلة البرمجية==
يُميّز معامل الكتلة البرمجيّة باستخدام الرمز &، ويجب أن يكون الأخير ضمن تسلسل المعاملات:<syntaxhighlight lang="ruby">
يُميّز وسيط الكتلة البرمجيّة باستخدام الرمز <code>&</code>، ويجب أن يكون الأخير ضمن تسلسل الوسائط:<syntaxhighlight lang="ruby">
def my_method(&my_block)
def my_method(&my_block)
 my_block.call(self)
 my_block.call(self)
end
end
</syntaxhighlight>في أغلب الأحيان يستخدم هذا النوع من المعاملات لتمرير كتلة برمجيّة إلى تابع آخر:<syntaxhighlight lang="ruby">
</syntaxhighlight>في أغلب الأحيان، يستخدم هذا النوع من الوسائط لتمرير كتلة برمجيّة إلى تابع آخر:<syntaxhighlight lang="ruby">
def each_item(&block)
def each_item(&block)
 @items.each(&block)
 @items.each(&block)
end
end
</syntaxhighlight>إذا أردت فقط أن تنفّذ الكتلة البرمجيّة ولن تقوم بالمقابل بالتعديل عليها أو إرسالها إلى تابع آخر، فيفضّل حينها أن تستخدم الكلمة المحجوزة yield دون تحديد معامل معيّن. فالطريقة التالية تكافئ التابع الأوّل في هذه الفقرة:<syntaxhighlight lang="ruby">
</syntaxhighlight>إذا أردت فقط أن تنفّذ الكتلة البرمجيّة ولن تجري بالمقابل تعديلًا عليها أو إرسالها إلى تابع آخر، فيفضّل حينها أن تستخدم الكلمة المحجوزة <code>yield</code> دون تحديد وسيط معيّن. فالطريقة التالية تكافئ التابع الأوّل في هذه الفقرة:<syntaxhighlight lang="ruby">
def my_method
def my_method
 yield self
 yield self
end
end
</syntaxhighlight>وهناك فائدة أخرى على صعيد تحسين الأداء عند استخدام yield عوضًا عن الاستدعاء المباشر للكتلة، فعند إسناد معامل كتلة برمجية إلى متغيّر فسيسبّب ذلك إنشاء كائن من نوع Proc والذي سيبّب إيقاف تنفيذ الكتلة مؤقتًا. أمّا عند استخدام yield فلن يُنشأ كائن Proc هذا بالأساس.
</syntaxhighlight>وهناك فائدة أخرى على صعيد تحسين الأداء عند استخدام <code>yield</code> عوضًا عن الاستدعاء المباشر للكتلة؛ فعند إسناد وسيط كتلة برمجية إلى متغيّر، سيسبّب ذلك إنشاء كائن من النوع <code>[[Ruby/Proc|Proc]]</code> والذي سيبّب إيقاف تنفيذ الكتلة مؤقتًا. أمّا عند استخدام <code>yield</code>، فلن يُنشأ الكائن <code>[[Ruby/Proc|Proc]]</code> هذا بالأساس.


إذا كانت حاجتك إلى استخدام هذه الكتلة قليلة فبإمكانك حينئذٍ أن تستخدم Proc.new لإنشاء proc من الكتلة البرمجيّة والذي يمكن تمريره إلى التابع. انظر التوثيق الخاصّ بـ Proc.new لمزيد من التفاصيل.
إذا كانت حاجتك إلى استخدام هذه الكتلة قليلة، فبإمكانك حينئذٍ أن تستخدم <code>[[Ruby/Proc/new|Proc.new]]</code> لإنشاء <code>[[Ruby/Proc|proc]]</code> من الكتلة البرمجيّة والذي يمكن تمريره إلى التابع. انظر التوثيق الخاصّ بالتابع <code>[[Ruby/Proc/new|Proc.new]]</code> لمزيد من التفاصيل.
==التعامل مع الاستثناءات==
==التعامل مع الاستثناءات==
تحتوي التوابع على آلية تعامل مع الاستثناءات ضمنية، فلست بحاجة لاستخدام begin - end للتعامل مع الاستثناء. فهذا المثال: <syntaxhighlight lang="ruby">
تحتوي التوابع على آلية [[Ruby/exceptions|تعامل مع الاستثناءات]] ضمنية، فلست بحاجة لاستخدام <code>begin - end</code> للتعامل مع الاستثناء. فهذا المثال: <syntaxhighlight lang="ruby">
def my_method
def my_method
 begin
 begin
سطر 303: سطر 307:
 # التعامل مع الاستثناء
 # التعامل مع الاستثناء
end
end
</syntaxhighlight>إذا أردت تفادي استثناء فقط في جزء محدد من التابع فاستخدم حينها begin - end. لمزيد من التفاصيل ارجع إلى الصفحة الخاصة بالتعامل مع الاستثناءات.
</syntaxhighlight>إذا أردت تفادي استثناء في جزء محدد من التابع فقط، فاستخدم حينها <code>begin - end</code>. لمزيد من التفاصيل ارجع إلى الصفحة الخاصة [[Ruby/exceptions|بالتعامل مع الاستثناءات]].
=المصادر=
=المصادر=
<span> </span>
*[https://ruby-doc.org/core-2.5.1/doc/syntax/methods_rdoc.html صفحة Methods في توثيق روبي الرسمي.]
*[https://ruby-doc.org/core-2.5.1/doc/syntax/methods_rdoc.html صفحة Methods في توثيق روبي الرسمي.]
[[تصنيف: Ruby]]
[[تصنيف: Ruby Syntax]]

المراجعة الحالية بتاريخ 14:19، 18 نوفمبر 2018

تتضمّن التوابع في لغة روبي الوظائف التي يقوم بها برنامجك. إليك هذا المثال لتعريف تابع بسيط:

def one_plus_one
 1 + 1
end 

تعريف التابع يتكوّن من الكلمة المحجوزة def يتبعها اسم التابع، ثمّ جسم التابع، فالقيمة المعادة وفي النهاية الكلمة المحجوزة end. فعند تنفيذ التابع في المثال السابق، ستُعاد القيمة 2. هذا القسم سيغطّي تعريف التّوابع. ارجع إلى توثيق استدعاء التوابع لتتعرف على الصيغ المستخدمة لذلك الغرض.

تسمية التوابع

يمكن أن تستخدم لاسم التابع أحد المعاملات، وإلا فعليك أن تبتدئه بحرف أبجديّ أو أيّ محرف من محارف لوحة المفاتيح (أيضًا تعرف باسم محارف البتات الثمانية أي كل محرف بحجم 8 بت). ويمكن للاسم أن يتضمن أحرفًا وأرقامًا وشرطة سفليّة (_)، أو أيّ محرف من محارف البتات الثمانية. ومن المعتاد أن تستخدم الشرطة السفليّة لتفصل بين الكلمات في أسماء التوابع التي تتضمن كلمات عدّة.

def method_name
 puts "use underscores to separate words"
end

يجب أن تكتب البرامج بلغة روبي باستخدام مجموعات محارف متوافقة مع مجموعة المحارف US-ASCII مثل UTF-8 و ISO-8859-1. فإذا كان البتات الثمانية مضبوطة في مجموعات المحارف هذه، فهذا يدل على أنّ المحرف هو من المحارف الموسّعة، ولغة روبي تسمح أن تحتوي أسماء التوابع والمعرّفات الأخرى على تلك المحارف. إلا أنّ لغة روبي لا تسمح باستخدام بعض المحارف مثل ASCII NUL الذي رمزه ‎\x00. إليك بعض الأمثلة عن التوابع التي تصلح تسميتها في لغة روبي:

def hello
 "hello"
end
def こんにちは
 puts "means hello in Japanese"
end

وعادة ما تكون أسماء التوابع متوافقة مع نظام US-ASCII كون الحروف الخاصة به متوفرة على جميع لوحات المفاتيح. ويمكن لأسماء التوابع أن تنتهي بعلامة التعجّب ! أو علامة الاستفهام ? أو علامة المساواة =.

إن التوابع المنتهية بعلامة تعجب تستدعى وتُنفّذ مثل أيّ تابع آخر، إلّا أنّها عادة ما تصنّف كتوابع خطرة. ففي مكتبة نواة لغة روبي يُعدّ التّابع خطيرًا إذا كان يغيّر من قيمة المتغيّر الذي يستقبله، ولذلك يُميّز بعلامة التعجّب في آخره.

وفي هذه المكتبة يوجد لكلّ تابع من هذا النّوع تابعًا آخر مقابلًا ليس خطيرًا أي أنّه لا يغيّر من قيمة المتغيّر الذي يستقبله، وهذه التّوابع يكون لها نفس التسمية إلا أنّها لا تنتهي بإشارة التّعجب.

أمّا المتعارف عليه بالنّسبة للتوابع التي تنتهي تسميتها بإشارة استفهام فهي التوابع التي تُرجع قيمة منطقيّة، لكنّها لا تعيد بالضّرورة القيمة true أو false، بل غالبًا ما تعيد كائنًا يعبّر عن true أو قيمة الإيجاب.

والتوابع التي تنتهي بإشارة مساواة فهي توابع الإسناد؛ وبالنسبة لهذا النوع من التوابع، تُتجاهل القيمة المعادة وتُرجع معاملات التابع بدلًا منها.

فيما يلي أسماء التوابع المعبرة عن مختلف العمليات في لغة روبي، كلّ واحدة من هذه العمليات تقبل معاملًا واحدًا فقط. تجد بعد رمز العملية الاستخدام الشهير لها أو اسم العملية. لاحظ أنّك إن غيّرت ما تقوم به كلّ عمليّة فستسبّب لبسًا لدى المستخدم، إذ أنّ المتوقّع من إشارة الجمع أن تجمع، ومن إشارة الطرح أن تطرح، وهكذا. أضف إلى ذلك أنّك لن تتمكّن من تغيير أولويّة أيّ من هذه العمليات. 

المعامل العملية
+ جمع
- طرح
* ضرب
** قوة
/ قسمة
% باقي القسمة، أو سلسلة %
& العملية AND
^ العملية XOR
>> إزاحة لليمين
<< إزاحة لليسار، أو إضافة
== اختبار المساواة
=! اختبار عدم المساواة
=== المساواة التامة
~= مطابقة النمط (ليس خاصًّا بالتعبيرات النظامية فحسب)
~! عدم مطابقة النمط
<=> المقارنة والمعروف أيضًا بمعامل سفينة الفضاء
> أصغر من
=> أصغر من أو يساوي
< أكبر من
=< أكبر من أو يساوي

لأجل تعريف توابع أحادية تغيّر سلوك إشارة الجمع والطرح والضرب والنفي المنطقي، عليك أن تُتبع رمز العملية بالرمز @ مثل: ‎+@‎ أو ‎!@‎ كما في المثال التالي:

class C
 def -@
   puts "you inverted this object"
 end
end
obj = C.new
-obj # "you inverted this object" يطبع

التوابع الأحادية لا تقبل أي معاملات. بالإضافة لذلك يمكن تعريف التوابع التي تستخدم للإشارة إلى العناصر وإسناد قيمٍ إليها بالشّكل [] أو ‎[]=‎ على التوالي وبالترتيب. وكلاهما بالإمكان أن يأخذ معاملًا واحدًا أو أكثر. ويمكن لتابع الإشارة للعناصر ألا يأخذ أيّ معامل. 

class C
 def [](a, b)
   puts a + b
 end
 def []=(a, b, c)
   puts a * b + c
 end
end
obj = C.new
obj[2, 3]     # "5" يطبع
obj[2, 3] = 4 # "10" يطبع

القيم المعادة

تُعيد التوابع بشكل افتراضيّ آخر تعبير برمجيّ يصل إليه التنفيذ في جسم التابع؛ في المثال أعلاه، التعبير الأخير (والوحيد) الذي نُفّذ كان عمليّة جمع بسيطة 1+1. ويمكن أيضًا استخدام الكلمة المحجوزة return للتأكيد بأنّ يعيد التابع القيمة التي تليها.

def one_plus_one
 return 1 + 1
end

كما يمكن استخدام كلمة return لإنهاء تنفيذ التابع دون إكمال التعبيرات البرمجيّة التي تليها.

def two_plus_two
 return 2 + 2
 1 + 1  # لا يتمّ تنفيذ هذا السطر أبدًا
end

لاحظ أنّه - كما أشرنا سابقًا - في حالة توابع الإسناد، فإنّ القيمة المعادة تُتجاهل ويعيد التابع بدلًا منها المعامل الذي مُرّر إليه:

def a=(value)
 return 1 + value
end
p(self.a = 5) # تطبع5

أمّا القيمة المعادة فترجع فقط في حالة استدعاء التابع بشكل مباشر:

p send(:a=, 5) # تطبع 6

النطاق

الصيغة النظامية لتعريف تابع:

def my_method
 # ...
end

وبهذه الطريقة تضيف تابعًا إلى صنف (class). كما يمكنك تعريف تابع لأغراض صنف معين وذلك بإضافة كلمة class:

class C
 def my_method
   # ...
 end
end

كما يمكن تعريف تابع لكائن آخر. وتستطيع تعريف تابع للصنف نفسه (وليس للكائنات المتفرعة عنه) كالتالي:

class C
 def self.my_method
   # ...
 end
end

وهذه الطريقة تُعد حالة خاصة من إحدى قواعد الصيغة في لغة روبي، وهي القدرة على إضافة تابع لأيّ كائن. وبما أنّ الأصناف بحدّ ذاتها هي نوع من الكائنات، فبالإمكان ببساطة إضافة تابع إلى كائن الصنف وفيما يلي صيغة إضافة تابع إلى كائن ما:

greeting = "Hello"
def greeting.broaden
 self + ", world!"
end
greeting.broaden # تعيد "Hello, world!"

كلمة self هي كلمة محجوزة في اللغة تشير إلى الغرض الحالي من وجهة نظر مفسّر اللغة، فهي تسهّل تعريف تابع الصنف في المثال السابق.

def String.hello
 "Hello, world!"
end

تعريف التابع بهذا الشكل يسمى "التابع المنفرد" (singleton method). فالتابع broaden في المثال السابق موجود في الكائن greeting فحسب، ولن تجده في أيّ متغيّر آخر من نوع السلسلة النصية string.

إعادة التعريف

عندما يصادف مفسّر لغة روبي كلمة def قبل اسم تابع معرّف مسبقًا فإنّه لا يعدّ ذلك خطأ وإنّما يعيد تعريف هذا التابع. وهذا ما يسمّى بإعادة التعريف (Overriding). إلّا أنّ هذه الإمكانيّة في لغة روبي تُعدّ خطرة ولا يستحسن استخدامها بشكل متكّرر، إلا في حالة توسيع أصناف اللغة الأساسية (core classes)، لأنّها قد تؤدي إلى نتائج غير معروفة. خذ على سبيل المثال تسلسل الأوامر التالي:

>> "43".to_i
=> 43
>> class String
>>   def to_i
>>     42
>>   end
>> end
=> nil
>> "43".to_i
=> 42

هذا سيسبب بكلّ تأكيد تخريبًا لأيّ شيفرة تستخدم التابع to_i من الصنف String لاستخلاص أعدادٍ من سلسلة نصية.

وسائط التوابع

يمكن للتابع أن يقبل وسائط وتكون مكتوبة على التتالي بعد اسم التابع:

def add_one(value)
 value + 1
end

عند استدعاء التابع add_one، يجب على المستخدم أن يمرّر له وسيطًا، وهذا الوسيط هو متغيّر محليّ ضمن جسم التابع. ففي المثال السابق، يضيف التابع واحدًا إلى هذا الوسيط الذي مُرّر إليه، ويُعيد الناتج. فإذا أُعطي التابع 1 سيعيد 2. والأقواس المحيطة بالوسائط اختيارية ويمكن حذفها:

def add_one value
 value + 1
end

وإذا كان لديك أكثر من وسيط، فافصل بينها بفواصل:

def add_values(a, b)
 a + b
end

فعند الاستدعاء، يجب تمرير الوسائط بنفس الترتيب؛ بعيارة أخرى، يمكن القول أنّ الوسائط حساسة للترتيب.

القيم الافتراضية

يمكن أن تحصل الوسائط على قيم افتراضية:

def add_values(a, b = 1)
 a + b
end

ولا يشترط أن تكون القيمة الافتراضية في بداية أو نهاية الوسائط، إلّا أن الوسائط ذات القيم الافتراضية يجب أن تجمّع معًا، فالمثال التالي مقبول:

def add_values(a = 1, b = 2, c)
 a + b + c
end

أما هذا المثال، فسيعطي الخطأ SyntaxError:

def add_values(a = 1, b, c = 1)
 a + b + c
end

تفكيك المصفوفة

يمكنك تفكيك مصفوفة (أوس استخراج القيم منها) باستخدام أقواس مضاعفة في معاملات التابع:

def my_method((a, b))
 p a: a, b: b
end
my_method([1, 2])

هذا المثال يطبع:

{:a=>1, :b=>2} 

ويُتجاهل كلّ عنصر في المصفوفة زائد على عدد الوسائط.

def my_method((a, b))
 p a: a, b: b
end
my_method([1, 2, 3])

وهذا المثال له نفس نتيجة المثال السابق. يمكنك استخدام الرمز * لتحصيل الوسائط المتبقية أيًا كان عددها في المصفوفة؛ فالمثال التالي يفصل المصفوفة ليسند أول عنصر منها في الوسيط الأول، والباقي يسنده كمصفوفة إلى الوسيط الثاني:

def my_method((a, *b))
 p a: a, b: b
end
my_method([1, 2, 3])

هذا المثال يطبع:

{:a=>1, :b=>[2, 3]}

أيّ وسيط يستجيب للتابع to_ary يمكن استخدامه في عملية التفكيك هذه. فإذا كان لديك كائن آخر تريد أن تفكّكه بنفس الطريقة، فعليك أن تعرّف له التابع to_ary الخاص به. يمكنك استخدام أقواس ضمنية لتفكيك مصفوفة مُرّرت كوسيط، لكن إذا لم يكن الوسيط المقابل له من نوع مصفوفة، فسوف يُسند هذا الوسيط إلى الوسيط الأول ضمن قوسي التفكيك، بينما تأخذ بقية الوسائط القيمة nil:

def my_method(a, (b, c), d)
 p a: a, b: b, c: c, d: d
end
my_method(1, 2, 3)

هذا المثال يطبع:

{:a=>1, :b=>2, :c=>nil, :d=>3}

كما بإمكانك تضمين عمليات التفكيك داخل بعضها بأي شكل:

def my_method(((a, b), c))
 # ...
end

الوسائط التي من النوع: مصفوفة وجدول Hash

إضافة الرمز * في بداية اسم الوسيط يسبب تحويل جميع الوسائط الإضافية إلى مصفوفة:

def gather_arguments(*arguments)
 p arguments
end
gather_arguments 1, 2, 3 # [1, 2, 3] تطبع

ويجب أن يأتي هذا الوسيط في آخر الوسائط الموضعية وعليه أن يسبق أيّ وسيط مسمى. كما يمكن للمصفوفة الناتجة أن تتضمّن جدول Hash في نهايتها إذا مُرّر هذا النوع عند الاستدعاء بعد جميع الوسائط الموضعية. 

gather_arguments 1, a: 2 # [1, {:a=>2}] تطبع

إلّا أنّ هذه الحالة تحصل فقط عندما لا يعرّف التابع أيّ وسائط من نوع "الوسائط المسماة".

def gather_arguments_keyword(*positional, keyword: nil)
p positional: positional, keyword: keyword
end
gather_arguments_keyword 1, 2, three: 3
#=> unknown keyword: three (ArgumentError):تسبب ظهور خطأ
# لاحظ أيضًا أنّ استخدام الرمز * وحده يسبب تجاهل أيّ معاملات.
def ignore_arguments(*)
end

الوسائط المسماة

الوسائط المسماة تشبه في آلية عملها الوسائط الموضعية ذات القيم الافتراضية:

def add_values(first: 1, second: 2)
 first + second
end

يمكن قبول أيّ عدد من الوسائط المسماة باستخدام الرمز ** قبل اسم الوسيط:

def gather_arguments(first: nil, **rest)
 p first, rest
end
gather_arguments first: 1, second: 2, third: 3
# {:second=>2, :third=>3} تطبع 1 ثم

عند استدعاء تابع مع وسائط مسماة، فمن الممكن لها أن تأتي ضمن أيّ ترتيب، إلّا أنّ الوسائط غير المعرفة مسبقًا ستسبب ظهور خطأ من النوع ArgumentError.

وفي حال رغبتك باستخدام وسائط مسماة مع وسائط موضعية، فعليك أن تكتب جميع الوسائط الموضعية قبل أيّ وسيط مسمى.

وسائط الكتلة البرمجية

يُميّز وسيط الكتلة البرمجيّة باستخدام الرمز &، ويجب أن يكون الأخير ضمن تسلسل الوسائط:

def my_method(&my_block)
 my_block.call(self)
end

في أغلب الأحيان، يستخدم هذا النوع من الوسائط لتمرير كتلة برمجيّة إلى تابع آخر:

def each_item(&block)
 @items.each(&block)
end

إذا أردت فقط أن تنفّذ الكتلة البرمجيّة ولن تجري بالمقابل تعديلًا عليها أو إرسالها إلى تابع آخر، فيفضّل حينها أن تستخدم الكلمة المحجوزة yield دون تحديد وسيط معيّن. فالطريقة التالية تكافئ التابع الأوّل في هذه الفقرة:

def my_method
 yield self
end

وهناك فائدة أخرى على صعيد تحسين الأداء عند استخدام yield عوضًا عن الاستدعاء المباشر للكتلة؛ فعند إسناد وسيط كتلة برمجية إلى متغيّر، سيسبّب ذلك إنشاء كائن من النوع Proc والذي سيبّب إيقاف تنفيذ الكتلة مؤقتًا. أمّا عند استخدام yield، فلن يُنشأ الكائن Proc هذا بالأساس.

إذا كانت حاجتك إلى استخدام هذه الكتلة قليلة، فبإمكانك حينئذٍ أن تستخدم Proc.new لإنشاء proc من الكتلة البرمجيّة والذي يمكن تمريره إلى التابع. انظر التوثيق الخاصّ بالتابع Proc.new لمزيد من التفاصيل.

التعامل مع الاستثناءات

تحتوي التوابع على آلية تعامل مع الاستثناءات ضمنية، فلست بحاجة لاستخدام begin - end للتعامل مع الاستثناء. فهذا المثال: 

def my_method
 begin
   # شيفرة قد تسبب ظهور استثناءات
 rescue
   # التعامل مع الاستثناء
 end
end

يمكن كتابته بالشكل التالي:

def my_method
 # شيفرة قد تسبب ظهور استثناء
rescue
 # التعامل مع الاستثناء
end

إذا أردت تفادي استثناء في جزء محدد من التابع فقط، فاستخدم حينها begin - end. لمزيد من التفاصيل ارجع إلى الصفحة الخاصة بالتعامل مع الاستثناءات.

المصادر