الفرق بين المراجعتين ل"Ruby/methods"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
ط (تنسيق بعض الأخطاء في الأكواد)
ط (مراجعة وتدقيق.)
 
(3 مراجعات متوسطة بواسطة مستخدم واحد آخر غير معروضة)
سطر 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>
+
</syntaxhighlight>تعريف التابع يتكوّن من الكلمة المحجوزة <code>def</code> يتبعها اسم التابع، ثمّ جسم التابع، فالقيمة المعادة وفي النهاية الكلمة المحجوزة <code>end</code>. فعند تنفيذ التابع في المثال السابق، ستُعاد القيمة 2. هذا القسم سيغطّي تعريف التّوابع. ارجع إلى توثيق [[Ruby/calling methods|استدعاء التوابع]] لتتعرف على الصيغ المستخدمة لذلك الغرض.
تعريف التابع يتكوّن من الكلمة المحجوزة def يتبعها اسم التابع، ثمّ جسم التابع، فالقيمة المعادة وفي النهاية الكلمة المحجوزة end. فعند تنفيذ التابع في المثال  السابق ستُرجع القيمة 2.
+
==تسمية التوابع==
هذا القسم سيغطّي تعريف التّوابع. ارجع إلى توصيف استدعاء التوابع لتتعرف على الصيغ المستخدمة لذلك.
+
يمكن أن تستخدم لاسم التابع أحد المعاملات، وإلا فعليك أن تبتدئه بحرف أبجديّ أو أيّ محرف من محارف لوحة المفاتيح (أيضًا تعرف باسم محارف البتات الثمانية أي كل محرف بحجم 8 بت). ويمكن للاسم أن يتضمن أحرفًا وأرقامًا وشرطة سفليّة (_)، أو أيّ محرف من محارف البتات الثمانية. ومن المعتاد أن تستخدم الشرطة السفليّة لتفصل بين الكلمات في أسماء التوابع التي تتضمن كلمات عدّة.<syntaxhighlight lang="ruby">
== تسمية التوابع ==
 
يمكن أن تستخدم لاسم التابع أحد المعاملات، وإلا فعليك أن تبتدئه بحرف أبجديّ أو أيّ محرف من محارف لوحة المفاتيح (أيضًا تعرف باسم محارف البتات الثمانية). ويمكن للاسم أن يتضمن أحرفًا وأرقامًا وشرطة سفليّة أو أيّ محرف من محارف البتات الثمانية. ومن المعتاد أن تستخدم الشرطة السفليّة لتفصل بين الكلمات في أسماء التوابع التي تتضمن كلمات عدّة.
 
<syntaxhighlight lang="ruby">
 
 
def method_name
 
def method_name
 
 puts "use underscores to separate words"
 
 puts "use underscores to separate words"
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>يجب أن تكتب البرامج بلغة روبي باستخدام مجموعات محارف متوافقة مع مجموعة المحارف [[Arduino/asciichart|US-ASCII]] مثل UTF-8 و ISO-8859-1. فإذا كان البتات الثمانية مضبوطة في مجموعات المحارف هذه، فهذا يدل على أنّ المحرف هو من المحارف الموسّعة، ولغة روبي تسمح أن تحتوي أسماء التوابع والمعرّفات الأخرى على تلك المحارف. إلا أنّ لغة روبي لا تسمح باستخدام بعض المحارف مثل [[Arduino/asciichart|ASCII NUL]] الذي رمزه ‎\x00.
يجب أن تكتب البرامج بلغة روبي باستخدام مجموعات محارف متوافقة مع مجموعة المحارف US-ASCII مثل UTF-8 و ISO-8859-1. فإذا كان البتات الثمانية مضبوطة في مجموعات المحارف هذه، فهذا يدل على أنّ المحرف هو من المحارف الموسّعة، ولغة روبي تسمح أن تحتوي أسماء التوابع والمعرّفات الأخرى على تلك المحارف. إلا أنّ لغة روبي لا تسمح باستخدام بعض المحارف مثل ASCII NUL الذي رمزه ‎\x00.
+
 
إليك بعض الأمثلة عن التوابع التي تصلح تسميتها في لغة روبي:
+
إليك بعض الأمثلة عن التوابع التي تصلح تسميتها في لغة روبي:<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
 
 
def hello
 
def hello
 
 "hello"
 
 "hello"
سطر 24: سطر 19:
 
 puts "means hello in Japanese"
 
 puts "means hello in Japanese"
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>وعادة ما تكون أسماء التوابع متوافقة مع نظام [[Arduino/asciichart|US-ASCII]] كون الحروف الخاصة به متوفرة على جميع لوحات المفاتيح. ويمكن لأسماء التوابع أن تنتهي بعلامة التعجّب <code>!</code> أو علامة الاستفهام <code>?</code> أو علامة المساواة <code>=</code>.
وعادة ما تكون أسماء التوابع متوافقة مع نظام US-ASCII كون الحروف الخاصة به متوفرة على جميع لوحات المفاتيح.
 
ويمكن لأسماء التوابع أن تنتهي بعلامة التعجّب ! أو علامة الاستفهام ? أو علامة المساواة = .
 
إن التوابع المنتهية بعلامة تعجب تستدعى وتُنفّذ مثل أيّ تابع آخر، إلّا أنّها عادة ما تصنّف كتوابع خطرة. ففي مكتبة نواة لغة روبي يُعدّ التّابع خطيرًا إذا كان يغيّر من قيمة المتغيّر الذي يستقبله، ولذلك يُميّز بعلامة التعجّب في آخره. وفي هذه المكتبة يوجد لكلّ تابع من هذا النّوع تابعًا آخر مقابلًا ليس خطيرًا أي أنّه لا يغيّر من قيمة المتغيّر الذي يستقبله، وهذه التّوابع يكون لها نفس التسمية إلا أنّها لا تنتهي بإشارة التّعجب.
 
أمّا المتعارف عليه بالنّسبة للتوابع التي تنتهي تسميتها بإشارة استفهام فهي التوابع التي تُرجع قيمة منطقيّة، لكنّها ليست بالضّرورة تعيد true أو false، بل غالبًا ما تعيد كائنًا يعبّر عن true أو قيمة الإيجاب.
 
والتوابع التي تنتهي بإشارة مساواة فهي توابع الإسناد، وبالنسبة لهذا النوع من التوابع تُتجاهل القيمة المعادة وتُرجع معاملات التابع بدلًا منها.
 
فيما يلي أسماء التوابع المعبرة عن مختلف العمليات في لغة روبي، كلّ واحدة من هذه العمليات تقبل معاملًا واحدًا فقط. تجد بعد رمز العملية الاستخدام الشهير لها أو اسم العملية. لاحظ أنّك إن غيّرت ما تقوم به كلّ عمليّة فستسبّب لبسًا لدى المستخدم، إذ أنّ المتوقّع من إشارة الجمع أن تجمع، ومن إشارة الطرح أن تطرح، وهكذا. أضف إلى ذلك أنّك لن تتمكّن من تغيير أولويّة أيّ من هذه العمليات. 
 
<syntaxhighlight lang="text">
 
+
 
جمع
 
  
-
+
إن التوابع المنتهية بعلامة تعجب تستدعى وتُنفّذ مثل أيّ تابع آخر، إلّا أنّها عادة ما تصنّف كتوابع خطرة. ففي مكتبة نواة لغة روبي يُعدّ التّابع خطيرًا إذا كان يغيّر من قيمة المتغيّر الذي يستقبله، ولذلك يُميّز بعلامة التعجّب في آخره.
طرح
 
  
*
+
وفي هذه المكتبة يوجد لكلّ تابع من هذا النّوع تابعًا آخر مقابلًا ليس خطيرًا أي أنّه لا يغيّر من قيمة المتغيّر الذي يستقبله، وهذه التّوابع يكون لها نفس التسمية إلا أنّها لا تنتهي بإشارة التّعجب.
ضرب
 
  
**
+
أمّا المتعارف عليه بالنّسبة للتوابع التي تنتهي تسميتها بإشارة استفهام فهي التوابع التي تُرجع قيمة منطقيّة، لكنّها لا تعيد بالضّرورة القيمة <code>true</code> أو <code>false</code>، بل غالبًا ما تعيد كائنًا يعبّر عن <code>true</code> أو قيمة الإيجاب.
قوة
 
  
/
+
والتوابع التي تنتهي بإشارة مساواة فهي توابع الإسناد؛ وبالنسبة لهذا النوع من التوابع، تُتجاهل القيمة المعادة وتُرجع معاملات التابع بدلًا منها.
قسمة
 
  
%
+
فيما يلي أسماء التوابع المعبرة عن مختلف العمليات في لغة روبي، كلّ واحدة من هذه العمليات تقبل معاملًا واحدًا فقط. تجد بعد رمز العملية الاستخدام الشهير لها أو اسم العملية. لاحظ أنّك إن غيّرت ما تقوم به كلّ عمليّة فستسبّب لبسًا لدى المستخدم، إذ أنّ المتوقّع من إشارة الجمع أن تجمع، ومن إشارة الطرح أن تطرح، وهكذا. أضف إلى ذلك أنّك لن تتمكّن من تغيير أولويّة أيّ من هذه العمليات. 
باقي القسمة، أو سلسلة %
+
{| class="wikitable"
 
+
!المعامل
&
+
!العملية
AND
+
|-
 
+
|<nowiki>+</nowiki>
^
+
|جمع
OR الحصرية
+
|-
 
+
|<nowiki>-</nowiki>
>>
+
|طرح
إزاحة لليمين
+
|-
 
+
|*
<<
+
|ضرب
إزاحة لليسار، أو إضافة
+
|-
 
+
|**
==
+
|قوة
اختبار المساواة
+
|-
 
+
|/
!=
+
|قسمة
اختبار عدم المساواة
+
|-
 
+
|%
===
+
|باقي القسمة، أو سلسلة %
المساواة التامة
+
|-
 
+
|&
=~
+
|العملية AND
مطابقة النمط (ليس خاصًّا بالتعبيرات النظامية فحسب)
+
|-
 
+
|^
!~
+
|العملية XOR
عدم مطابقة النمط
+
|-
 
+
|>>
<=>
+
|إزاحة لليمين
المقارنة والمعروف أيضًا بمعامل سفينة الفضاء
+
|-
 
+
|<<
<
+
|إزاحة لليسار، أو إضافة
أصغر من
+
|-
 
+
|==
<=
+
|اختبار المساواة
أصغر من أو يساوي
+
|-
 
+
|=!
>
+
|اختبار عدم المساواة
أكبر من
+
|-
 
+
|===
>=
+
|المساواة التامة
أكبر من أو يساوي
+
|-
</syntaxhighlight>
+
|~=
لأجل تعريف توابع أحادية تغيّر سلوك إشارة الجمع والطرح والضرب والنفي المنطقي، عليك أن تُتبع رمز العملية بالرمز @ مثل: ‎+@‎ أو ‎!@‎ كما في المثال التالي:
+
|مطابقة النمط (ليس خاصًّا بالتعبيرات النظامية فحسب)
<syntaxhighlight lang="ruby">
+
|-
 +
|~!
 +
|عدم مطابقة النمط
 +
|-
 +
|<=>
 +
|المقارنة والمعروف أيضًا بمعامل سفينة الفضاء
 +
|-
 +
|>
 +
|أصغر من
 +
|-
 +
|=>
 +
|أصغر من أو يساوي
 +
|-
 +
|<
 +
|أكبر من
 +
|-
 +
|=<
 +
|أكبر من أو يساوي
 +
|}
 +
لأجل تعريف توابع أحادية تغيّر سلوك إشارة الجمع والطرح والضرب والنفي المنطقي، عليك أن تُتبع رمز العملية بالرمز <code>@</code> مثل: ‎<code>+@</code>‎ أو ‎<code>!@‎</code> كما في المثال التالي:<syntaxhighlight lang="ruby">
 
class C
 
class C
 
 def -@
 
 def -@
سطر 101: سطر 102:
 
obj = C.new
 
obj = C.new
 
-obj # "you inverted this object" يطبع
 
-obj # "you inverted this object" يطبع
</syntaxhighlight>
+
</syntaxhighlight>التوابع الأحادية لا تقبل أي معاملات. بالإضافة لذلك يمكن تعريف التوابع التي تستخدم للإشارة إلى العناصر وإسناد قيمٍ إليها بالشّكل <code>[]</code> أو <code>‎[]=</code>‎ على التوالي وبالترتيب. وكلاهما بالإمكان أن يأخذ معاملًا واحدًا أو أكثر. ويمكن لتابع الإشارة للعناصر ألا يأخذ أيّ معامل. <syntaxhighlight lang="ruby">
التوابع الأحادية لا تقبل أي معاملات.
 
بالإضافة لذلك يمكن تعريف التوابع التي تستخدم للإشارة إلى العناصر وإسناد قيمٍ إليها بالشّكل [] أو ‎[]=‎ على التوالي وبالترتيب. وكلاهما بالإمكان أن يأخذ معاملًا واحدًا أو أكثر. ويمكن لتابع الإشارة للعناصر ألا يأخذ أيّ معامل. 
 
<syntaxhighlight lang="ruby">
 
 
class C
 
class C
 
 def [](a, b)
 
 def [](a, b)
سطر 117: سطر 115:
 
obj[2, 3] = 4 # "10" يطبع
 
obj[2, 3] = 4 # "10" يطبع
 
</syntaxhighlight>
 
</syntaxhighlight>
== القيم المعادة ==
+
==القيم المعادة==
تُعيد التوابع بشكل افتراضيّ آخر تعبير برمجيّ يصل إليه التنفيذ في جسم التابع، ففي المثال أعلاه، فالتعبير الأخير (والوحيد) الذي نُفّذ كان عمليّة جمع بسيطة 1+1. ويمكن أيضًا استخدام الكلمة المحجوزة return للتأكيد بأنّ التابع يعيد قيمة.
+
تُعيد التوابع بشكل افتراضيّ آخر تعبير برمجيّ يصل إليه التنفيذ في جسم التابع؛ في المثال أعلاه، التعبير الأخير (والوحيد) الذي نُفّذ كان عمليّة جمع بسيطة 1+1. ويمكن أيضًا استخدام الكلمة المحجوزة <code>return</code> للتأكيد بأنّ يعيد التابع القيمة التي تليها.<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
 
 
def one_plus_one
 
def one_plus_one
 
 return 1 + 1
 
 return 1 + 1
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>كما يمكن استخدام كلمة <code>return</code> لإنهاء تنفيذ التابع دون إكمال التعبيرات البرمجيّة التي تليها.<syntaxhighlight lang="ruby">
كما يمكن استخدام كلمة return لإنهاء تنفيذ التابع دون إكمال التعبيرات البرمجيّة التي تليها.
 
<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>لاحظ أنّه - كما أشرنا سابقًا - في حالة توابع الإسناد، فإنّ القيمة المعادة تُتجاهل ويعيد التابع بدلًا منها المعامل الذي مُرّر إليه:<syntaxhighlight lang="ruby">
لاحظ أنّه - كما أشرنا سابقًا - في حالة توابع الإسناد فإنّ القيمة المعادة تُتجاهل ويعيد التابع بدلًا منها المعامل الذي مُرّر إليه:
 
<syntaxhighlight lang="ruby">
 
 
def a=(value)
 
def a=(value)
 
 return 1 + value
 
 return 1 + value
 
end
 
end
 
p(self.a = 5) # تطبع5
 
p(self.a = 5) # تطبع5
</syntaxhighlight>
+
</syntaxhighlight>أمّا القيمة المعادة فترجع فقط في حالة استدعاء التابع بشكل مباشر:<syntaxhighlight lang="ruby">
أمّا القيمة المعادة فترجع فقط في حالة استدعاء التابع بشكل مباشر:
 
<syntaxhighlight lang="ruby">
 
 
p send(:a=, 5) # تطبع 6
 
p send(:a=, 5) # تطبع 6
 
</syntaxhighlight>
 
</syntaxhighlight>
== النطاق ==
+
==النطاق==
الصيغة النظامية لتعريف تابع:
+
الصيغة النظامية لتعريف تابع:<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
 
 
def my_method
 
def my_method
 
 # ...
 
 # ...
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>وبهذه الطريقة تضيف تابعًا إلى صنف (class). كما يمكنك تعريف تابع لأغراض صنف معين وذلك بإضافة كلمة class:<syntaxhighlight lang="ruby">
وبهذه الطريقة تضيف تابعًا إلى صنف class. كما يمكنك تعريف تابع لأغراض صنف معين وذلك بإضافة كلمة class:
 
<syntaxhighlight lang="ruby">
 
 
class C
 
class C
 
 def my_method
 
 def my_method
سطر 156: سطر 144:
 
 end
 
 end
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>كما يمكن تعريف تابع لكائن آخر. وتستطيع تعريف تابع للصنف نفسه (وليس للكائنات المتفرعة عنه) كالتالي:<syntaxhighlight lang="ruby">
كما يمكن تعريف تابع لكائن آخر. وتستطيع تعريف تابع للصنف نفسه (وليس للكائنات المتفرعة عنه) كالتالي:
 
<syntaxhighlight lang="ruby">
 
 
class C
 
class C
 
 def self.my_method
 
 def self.my_method
سطر 164: سطر 150:
 
 end
 
 end
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>وهذه الطريقة تُعد حالة خاصة من إحدى قواعد الصيغة في لغة روبي، وهي القدرة على إضافة تابع لأيّ كائن. وبما أنّ الأصناف بحدّ ذاتها هي نوع من الكائنات، فبالإمكان ببساطة إضافة تابع إلى كائن الصنف
وهذه الطريقة تُعد حالة خاصة من إحدى قواعد الصيغة في لغة روبي، وهي القدرة على إضافة تابع لأيّ كائن، وبما أنّ الأصناف بحدّ ذاتها هي نوع من الكائنات فبالإمكان ببساطة إضافة تابع إلى كائن الصنف
+
 
وفيما يلي صيغة إضافة تابع إلى كائن ما:
+
وفيما يلي صيغة إضافة تابع إلى كائن ما:<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
 
 
greeting = "Hello"
 
greeting = "Hello"
 
def greeting.broaden
 
def greeting.broaden
سطر 173: سطر 158:
 
end
 
end
 
greeting.broaden # تعيد "Hello, world!"
 
greeting.broaden # تعيد "Hello, world!"
</syntaxhighlight>
+
</syntaxhighlight>كلمة <code>self</code> هي كلمة محجوزة في اللغة تشير إلى الغرض الحالي من وجهة نظر مفسّر اللغة، فهي تسهّل تعريف تابع الصنف في المثال السابق.<syntaxhighlight lang="ruby">
كلمة self هي كلمة محجوزة في اللغة تشير إلى الغرض الحالي من وجهة نظر مفسّر اللغة، فهي تسهّل تعريف تابع الصنف في المثال السابق.
 
<syntaxhighlight lang="ruby">
 
 
def String.hello
 
def String.hello
 
 "Hello, world!"
 
 "Hello, world!"
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>تعريف التابع بهذا الشكل يسمى "التابع المنفرد" (singleton method). فالتابع <code>broaden</code> في المثال السابق موجود في الكائن <code>greeting</code> فحسب، ولن تجده في أيّ متغيّر آخر من نوع السلسلة النصية <code>string</code>.
تعريف التابع بهذا الشكل يسمى "التابع المنفرد singleton method". فالتابع broaden في المثال السابق موجود في الكائن greeting فحسب، ولن تجده في أيّ متغيّر آخر من نوع السلسلة النصية string.
+
==إعادة التعريف==
== إعادة التعريف ==
+
عندما يصادف مفسّر لغة روبي كلمة <code>def</code> قبل اسم تابع معرّف مسبقًا فإنّه لا يعدّ ذلك خطأ وإنّما يعيد تعريف هذا التابع. وهذا ما يسمّى بإعادة التعريف (Overriding). إلّا أنّ هذه الإمكانيّة في لغة روبي تُعدّ خطرة ولا يستحسن استخدامها بشكل متكّرر، إلا في حالة توسيع أصناف اللغة الأساسية (core classes)، لأنّها قد تؤدي إلى نتائج غير معروفة. خذ على سبيل المثال تسلسل الأوامر التالي:<syntaxhighlight lang="text">
عندما يصادف مفسّر لغة روبي كلمة def قبل اسم تابع معرّف مسبقًا فإنّه لا يعدّ ذلك خطأ وإنّما يعيد تعريف هذا التابع. وهذا ما يسمّى بإعادة التعريف أو Overriding. إلّا أنّ هذه الإمكانيّة في لغة روبي تُعدّ خطرة ولا يستحسن استخدامها بشكل متكّرر، إلا في حالة توسيع أصناف اللغة الأساسية (core classes)، لأنّها قد تؤدي إلى نتائج غير معروفة. خذ على سبيل المثال تسلسل الأوامر التالي:
 
<syntaxhighlight lang="text">
 
 
>> "43".to_i
 
>> "43".to_i
 
=> 43
 
=> 43
سطر 194: سطر 175:
 
>> "43".to_i
 
>> "43".to_i
 
=> 42
 
=> 42
</syntaxhighlight>
+
</syntaxhighlight>هذا سيسبب بكلّ تأكيد تخريبًا لأيّ شيفرة تستخدم التابع <code>to_i</code> من الصنف <code>String</code> لاستخلاص أعدادٍ من سلسلة نصية.
هذا سيسبب بكلّ تأكيد تخريبًا لأيّ شيفرة تستخدم التابع to_i من الصنف String الذي يحوّل سلسلة المحارف إلى أرقام.
+
==وسائط التوابع==
== معاملات التوابع ==
+
يمكن للتابع أن يقبل وسائط وتكون مكتوبة على التتالي بعد اسم التابع:<syntaxhighlight lang="ruby">
يمكن للتابع أن يقبل معاملات وتكون مكتوبة على التتالي بعد اسم التابع:
 
<syntaxhighlight lang="ruby">
 
 
def add_one(value)
 
def add_one(value)
 
 value + 1
 
 value + 1
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>عند استدعاء التابع <code>add_one</code>، يجب على المستخدم أن يمرّر له وسيطًا، وهذا الوسيط هو متغيّر محليّ ضمن جسم التابع. ففي المثال السابق، يضيف التابع واحدًا إلى هذا الوسيط الذي مُرّر إليه، ويُعيد الناتج. فإذا أُعطي التابع 1 سيعيد 2.
عند استدعاء التابع add_one يجب على المستخدم أن يمرّر له معاملًا، وهذا المعامل هو متغيّر محليّ ضمن جسم التابع. ففي المثال السابق يضيف التابع واحدًا إلى هذا المعامل الذي مُرّر إليه، ويُعيد الناتج. فإذا أُعطي التابع 1 سيعيد 2.
+
 
والأقواس المحيطة بالمعاملات اختيارية ويمكن حذفها:
+
والأقواس المحيطة بالوسائط اختيارية ويمكن حذفها:<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
 
 
def add_one value
 
def add_one value
 
 value + 1
 
 value + 1
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>وإذا كان لديك أكثر من وسيط، فافصل بينها بفواصل:<syntaxhighlight lang="ruby">
وإذا كان لديك أكثر من معامل فافصل بينها بفواصل:
 
<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>ولا يشترط أن تكون القيمة الافتراضية في بداية أو نهاية الوسائط، إلّا أن الوسائط ذات القيم الافتراضية يجب أن تجمّع معًا، فالمثال التالي مقبول:<syntaxhighlight lang="ruby">
ولا يشترط أن تكون القيمة الافتراضية في بداية أو نهاية المعاملات، إلّا أن المعاملات ذات القيم الافتراضية يجب أن تجمّع معًا، فالمثال التالي مقبول:
 
<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>
+
</syntaxhighlight>أما هذا المثال، فسيعطي الخطأ <code>[[Ruby/SyntaxError|SyntaxError]]</code>:<syntaxhighlight lang="ruby">
أما هذا المثال فسيعطي خطأ في الصيغة SyntaxError
 
<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))
 
 p a: a, b: b
 
 p a: a, b: b
 
end
 
end
 
my_method([1, 2])
 
my_method([1, 2])
</syntaxhighlight>
+
</syntaxhighlight>هذا المثال يطبع:<syntaxhighlight lang="text">
هذا المثال يطبع:
 
<syntaxhighlight lang="text">
 
 
{:a=>1, :b=>2} 
 
{:a=>1, :b=>2} 
</syntaxhighlight>
+
</syntaxhighlight>ويُتجاهل كلّ عنصر في المصفوفة زائد على عدد الوسائط.<syntaxhighlight lang="ruby">
ويُتجاهل كلّ عنصر في المصفوفة زائد على عدد المعاملات.
 
<syntaxhighlight lang="ruby">
 
 
def my_method((a, b))
 
def my_method((a, b))
 
 p a: a, b: b
 
 p a: a, b: b
 
end
 
end
 
my_method([1, 2, 3])
 
my_method([1, 2, 3])
</syntaxhighlight>
+
</syntaxhighlight>وهذا المثال له نفس نتيجة المثال السابق.
وهذا المثال له نفس نتيجة المثال السابق.
+
 
يمكنك استخدام الرمز * لتحصيل المعاملات المتبقية أيًا كان عددها في المصفوفة، فالمثال التالي يفصل المصفوفة فيسند أول عنصر منها في المعامل الأول، والباقي يسند كمصفوفة في المعامل الثاني:
+
يمكنك استخدام الرمز <code>*</code> لتحصيل الوسائط المتبقية أيًا كان عددها في المصفوفة؛ فالمثال التالي يفصل المصفوفة ليسند أول عنصر منها في الوسيط الأول، والباقي يسنده كمصفوفة إلى الوسيط الثاني:<syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
 
 
def my_method((a, *b))
 
def my_method((a, *b))
 
 p a: a, b: b
 
 p a: a, b: b
 
end
 
end
 
my_method([1, 2, 3])
 
my_method([1, 2, 3])
</syntaxhighlight>
+
</syntaxhighlight>هذا المثال يطبع:<syntaxhighlight lang="text">
هذا المثال يطبع:
 
<syntaxhighlight lang="text">
 
 
{:a=>1, :b=>[2, 3]}
 
{:a=>1, :b=>[2, 3]}
</syntaxhighlight>
+
</syntaxhighlight>أيّ وسيط يستجيب للتابع <code>to_ary</code> يمكن استخدامه في عملية التفكيك هذه. فإذا كان لديك كائن آخر تريد أن تفكّكه بنفس الطريقة، فعليك أن تعرّف له التابع <code>to_ary</code> الخاص به.
أيّ معامل يستجيب للتابع to_ary يمكن استخدامه في عملية التفكيك هذه، فإذا كان لديك كائن آخر تريد أن تفكّكه بنفس الطريقة فعليك أن تعرّف له تابع to_ary الخاص به.
+
 
يمكنك استخدام أقواس ضمنية لتفكيك مصفوفة مُرّرت كأحد المعاملات، لكن إذا لم يكن المعامل المقابل له من نوع مصفوفة Array فسوف يُسند هذا المعامل إلى المعامل الأول ضمن قوسي التفكيك، بينما تأخذ بقية المعاملات قيمة nil:
+
يمكنك استخدام أقواس ضمنية لتفكيك مصفوفة مُرّرت كوسيط، لكن إذا لم يكن الوسيط المقابل له من نوع [[Ruby/Array|مصفوفة]]، فسوف يُسند هذا الوسيط إلى الوسيط الأول ضمن قوسي التفكيك، بينما تأخذ بقية الوسائط القيمة <code>nil</code>:<syntaxhighlight lang="ruby">
<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
 
end
 
end
 
my_method(1, 2, 3)
 
my_method(1, 2, 3)
</syntaxhighlight>
+
</syntaxhighlight>هذا المثال يطبع:<syntaxhighlight lang="text">
هذا المثال يطبع:
 
<syntaxhighlight lang="text">
 
 
{:a=>1, :b=>2, :c=>nil, :d=>3}
 
{:a=>1, :b=>2, :c=>nil, :d=>3}
</syntaxhighlight>
+
</syntaxhighlight>كما بإمكانك تضمين عمليات التفكيك داخل بعضها بأي شكل:<syntaxhighlight lang="ruby">
كما بإمكانك تضمين عمليات التفكيك داخل بعضها بأي شكل:
 
<syntaxhighlight lang="ruby">
 
 
def my_method(((a, b), c))
 
def my_method(((a, b), c))
 
 # ...
 
 # ...
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
== معاملات المصفوفة \ المصنّف ==
+
==الوسائط التي من النوع: مصفوفة وجدول Hash==
إضافة الرمز * في بداية اسم المعامل يسبب تحويل جميع المعاملات الإضافية إلى مصفوفة:
+
إضافة الرمز <code>*</code> في بداية اسم الوسيط يسبب تحويل جميع الوسائط الإضافية إلى مصفوفة:<syntaxhighlight lang="ruby">
<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>ويجب أن يأتي هذا الوسيط في آخر الوسائط الموضعية وعليه أن يسبق أيّ وسيط مسمى.
ويجب أن يأتي هذا المعامل في آخر المعاملات الموضعية وعليه أن يسبق أيّ معامل قيم مفتاحيّة.
+
 
كما يمكن للمصفوفة الناتجة أن تتضمّن مصنِّفًا في نهايتها إذا مُرّر هذا المصنّف عند الاستدعاء بعد جميع المعاملات الموضعي
+
كما يمكن للمصفوفة الناتجة أن تتضمّن [[Ruby/Hash|جدول Hash]] في نهايتها إذا مُرّر هذا النوع عند الاستدعاء بعد جميع الوسائط الموضعية. <syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
 
 
gather_arguments 1, a: 2 # [1, {:a=>2}] تطبع
 
gather_arguments 1, a: 2 # [1, {:a=>2}] تطبع
</syntaxhighlight>
+
</syntaxhighlight>إلّا أنّ هذه الحالة تحصل فقط عندما لا يعرّف التابع أيّ وسائط من نوع "الوسائط المسماة".<syntaxhighlight lang="ruby">
إلّا أنّ هذه الحالة تحصل فقط عندما لا يعرّف التابع أيّ معاملات من نوع القيم المفتاحية.
 
<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
سطر 305: سطر 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>يمكن قبول أيّ عدد من الوسائط المسماة باستخدام الرمز <code>**</code> قبل اسم الوسيط:<syntaxhighlight lang="ruby">
يمكن قبول أيّ عدد من معاملات القيم المفتاحية باستخدام الرمز ** قبل اسم المعامل:
 
<syntaxhighlight lang="ruby">
 
 
def gather_arguments(first: nil, **rest)
 
def gather_arguments(first: nil, **rest)
 
 p first, rest
 
 p first, rest
سطر 323: سطر 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>
+
</syntaxhighlight>عند استدعاء تابع مع وسائط مسماة، فمن الممكن لها أن تأتي ضمن أيّ ترتيب، إلّا أنّ الوسائط غير المعرفة مسبقًا ستسبب ظهور خطأ من النوع <code>[[Ruby/ArgumentError|ArgumentError]]</code>.
عند استدعاء تابع باستخدام القيم المفتاحية فمكن لها أن تأتي ضمن أيّ ترتيب، إلّا أنّ المعاملات غير المعرفة مسبقًا ستسبب ظهور خطأ من نوع ArgumentError
+
 
وفي حال رغبتك باستخدام معاملات قيم مفتاحية مع معاملات موضعية فعليك أن تكتب جميع المعاملات الموضعية قبل أيّ معامل قيمة مفتاحية.
+
وفي حال رغبتك باستخدام وسائط مسماة مع وسائط موضعية، فعليك أن تكتب جميع الوسائط الموضعية قبل أيّ وسيط مسمى.
== معاملات الكتلة البرمجية ==
+
==وسائط الكتلة البرمجية==
يُميّز معامل الكتلة البرمجيّة باستخدام الرمز &، ويجب أن يكون الأخير ضمن تسلسل المعاملات:
+
يُميّز وسيط الكتلة البرمجيّة باستخدام الرمز <code>&</code>، ويجب أن يكون الأخير ضمن تسلسل الوسائط:<syntaxhighlight lang="ruby">
<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>في أغلب الأحيان، يستخدم هذا النوع من الوسائط لتمرير كتلة برمجيّة إلى تابع آخر:<syntaxhighlight lang="ruby">
في أغلب الأحيان يستخدم هذا النوع من المعاملات لتمرير كتلة برمجيّة إلى تابع آخر:
 
<syntaxhighlight lang="ruby">
 
 
def each_item(&block)
 
def each_item(&block)
 
 @items.each(&block)
 
 @items.each(&block)
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>إذا أردت فقط أن تنفّذ الكتلة البرمجيّة ولن تجري بالمقابل تعديلًا عليها أو إرسالها إلى تابع آخر، فيفضّل حينها أن تستخدم الكلمة المحجوزة <code>yield</code> دون تحديد وسيط معيّن. فالطريقة التالية تكافئ التابع الأوّل في هذه الفقرة:<syntaxhighlight lang="ruby">
إذا أردت فقط أن تنفّذ الكتلة البرمجيّة ولن تقوم بالمقابل بالتعديل عليها أو إرسالها إلى تابع آخر، فيفضّل حينها أن تستخدم الكلمة المحجوزة yield دون تحديد معامل معيّن. فالطريقة التالية تكافئ التابع الأوّل في هذه الفقرة:
 
<syntaxhighlight lang="ruby">
 
 
def my_method
 
def my_method
 
 yield self
 
 yield self
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>وهناك فائدة أخرى على صعيد تحسين الأداء عند استخدام <code>yield</code> عوضًا عن الاستدعاء المباشر للكتلة؛ فعند إسناد وسيط كتلة برمجية إلى متغيّر، سيسبّب ذلك إنشاء كائن من النوع <code>[[Ruby/Proc|Proc]]</code> والذي سيبّب إيقاف تنفيذ الكتلة مؤقتًا. أمّا عند استخدام <code>yield</code>، فلن يُنشأ الكائن <code>[[Ruby/Proc|Proc]]</code> هذا بالأساس.
وهناك فائدة أخرى على صعيد تحسين الأداء عند استخدام yield عوضًا عن الاستدعاء المباشر للكتلة، فعند إسناد معامل كتلة برمجية إلى متغيّر فسيسبّب ذلك إنشاء كائن من نوع Proc والذي سيبّب إيقاف تنفيذ الكتلة مؤقتًا. أمّا عند استخدام yield فلن يُنشأ كائن Proc هذا بالأساس.
+
 
إذا كانت حاجتك إلى استخدام هذه الكتلة قليلة فبإمكانك حينئذٍ أن تستخدم 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 للتعامل مع الاستثناء. فهذا المثال: 
+
تحتوي التوابع على آلية [[Ruby/exceptions|تعامل مع الاستثناءات]] ضمنية، فلست بحاجة لاستخدام <code>begin - end</code> للتعامل مع الاستثناء. فهذا المثال: <syntaxhighlight lang="ruby">
<syntaxhighlight lang="ruby">
 
 
def my_method
 
def my_method
 
 begin
 
 begin
سطر 357: سطر 301:
 
 end
 
 end
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>يمكن كتابته بالشكل التالي:<syntaxhighlight lang="ruby">
يمكن كتابته بالشكل التالي:
 
<syntaxhighlight lang="ruby">
 
 
def my_method
 
def my_method
 
 # شيفرة قد تسبب ظهور استثناء
 
 # شيفرة قد تسبب ظهور استثناء
سطر 365: سطر 307:
 
 # التعامل مع الاستثناء
 
 # التعامل مع الاستثناء
 
end
 
end
</syntaxhighlight>
+
</syntaxhighlight>إذا أردت تفادي استثناء في جزء محدد من التابع فقط، فاستخدم حينها <code>begin - end</code>. لمزيد من التفاصيل ارجع إلى الصفحة الخاصة [[Ruby/exceptions|بالتعامل مع الاستثناءات]].
إذا أردت تفادي استثناء فقط في جزء محدد من التابع فاستخدم حينها begin - end. لمزيد من التفاصيل ارجع إلى الصفحة الخاصة بالتعامل مع الاستثناءات.
+
=المصادر=
 +
*[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. لمزيد من التفاصيل ارجع إلى الصفحة الخاصة بالتعامل مع الاستثناءات.

المصادر