الفرق بين المراجعتين لصفحة: «Ruby/calling methods»
نسخ الترجمة قبل تنسيقها |
تصحيح تنسيق الأكواد |
||
سطر 2: | سطر 2: | ||
= استدعاء التوابع في لغة روبي = | = استدعاء التوابع في لغة روبي = | ||
عندما تستدعي تابعًا، فإنّك تمرّر رسالة لكائن معيّن لأجل تنفيذ مهمّة معيّنة، ويتمّ ذلك في لغة روبي كالتّالي: | عندما تستدعي تابعًا، فإنّك تمرّر رسالة لكائن معيّن لأجل تنفيذ مهمّة معيّنة، ويتمّ ذلك في لغة روبي كالتّالي: | ||
<syntaxhighlight lang="ruby"> | |||
my_method() | my_method() | ||
</syntaxhighlight> | |||
لاحظ أنّ استخدام الأقواس المنحنية هنا اختياريّ: | لاحظ أنّ استخدام الأقواس المنحنية هنا اختياريّ: | ||
<syntaxhighlight lang="ruby"> | |||
my_method | my_method | ||
</syntaxhighlight> | |||
المعتمد في هذا التّوثيق أن تُستخدّم الأقواس عند وجود المعامِلات لإزالة الالتباس، إلا في حالة وجود فرق بين وجود الأقواس وحذفها. | المعتمد في هذا التّوثيق أن تُستخدّم الأقواس عند وجود المعامِلات لإزالة الالتباس، إلا في حالة وجود فرق بين وجود الأقواس وحذفها. | ||
سطر 15: | سطر 15: | ||
== المستقبِل == | == المستقبِل == | ||
المستقبِل الافتراضي في لغة روبي هو self وهو الذي يُستخدَم في حال عدم تحديد أيّ مستقبل آخر. ولأجل تحديد مستقبِل يستَدعى التابع بالشّكل التالي: | المستقبِل الافتراضي في لغة روبي هو self وهو الذي يُستخدَم في حال عدم تحديد أيّ مستقبل آخر. ولأجل تحديد مستقبِل يستَدعى التابع بالشّكل التالي: | ||
<syntaxhighlight lang="ruby"> | |||
my_object.my_method | my_object.my_method | ||
</syntaxhighlight> | |||
في هذه الحالة تُرسل رسالة my_method إلى الكائن my_object. فكلّ كائن يمكنه أن يكون مستقبِلًا لتابع ما، لكن حتى يتمّ ذلك يجب أن يكون التابع مرئيّ لهذا الكائن، وإلّا فسيظهر خطأ من نوع NoMethodError. | في هذه الحالة تُرسل رسالة my_method إلى الكائن my_object. فكلّ كائن يمكنه أن يكون مستقبِلًا لتابع ما، لكن حتى يتمّ ذلك يجب أن يكون التابع مرئيّ لهذا الكائن، وإلّا فسيظهر خطأ من نوع NoMethodError. | ||
سطر 28: | سطر 28: | ||
كلّ المعاملات في لغة روبي تُمرّر مرجعيًا ولا يؤجّل تقييمها. وكلّ معامل يُكتب متبوعًا بفاصلة , كالتّالي: | كلّ المعاملات في لغة روبي تُمرّر مرجعيًا ولا يؤجّل تقييمها. وكلّ معامل يُكتب متبوعًا بفاصلة , كالتّالي: | ||
<syntaxhighlight lang="ruby"> | |||
my_method(1, '2', :three) | my_method(1, '2', :three) | ||
</syntaxhighlight> | |||
يُمكن أن تكون المعاملات على شكل تعبير برمجي كالمصنِّفات (Hashes): | يُمكن أن تكون المعاملات على شكل تعبير برمجي كالمصنِّفات (Hashes): | ||
<syntaxhighlight lang="ruby"> | |||
'key' => value | 'key' => value | ||
</syntaxhighlight> | |||
أو معاملات القيم المفتاحية (Keyword arguments): | أو معاملات القيم المفتاحية (Keyword arguments): | ||
<syntaxhighlight lang="ruby"> | |||
key: value | key: value | ||
</syntaxhighlight> | |||
المصنِّفات ومعاملات القيم المفتاحية يجب أن تكون متجاورة ويجب أن تتلو المعاملات الموضعيّة، ولا بأس في أن تُخلط فيما بينها: | المصنِّفات ومعاملات القيم المفتاحية يجب أن تكون متجاورة ويجب أن تتلو المعاملات الموضعيّة، ولا بأس في أن تُخلط فيما بينها: | ||
<syntaxhighlight lang="ruby"> | |||
my_method('a' => 1, b: 2, 'c' => 3) | my_method('a' => 1, b: 2, 'c' => 3) | ||
</syntaxhighlight> | |||
== المعاملات الموضعيّة == | == المعاملات الموضعيّة == | ||
المعاملات الموضعيّة للرسالة تتبع اسم التابع مباشرة: | المعاملات الموضعيّة للرسالة تتبع اسم التابع مباشرة: | ||
<syntaxhighlight lang="ruby"> | |||
my_method(argument1, argument2) | my_method(argument1, argument2) | ||
</syntaxhighlight> | |||
في كثير من الحالات لا تكون الأقواس ضروريّة عند إرسال الرسالة: | في كثير من الحالات لا تكون الأقواس ضروريّة عند إرسال الرسالة: | ||
<syntaxhighlight lang="ruby"> | |||
my_method argument1, argument2 | my_method argument1, argument2 | ||
</syntaxhighlight> | |||
لكنّها ضروريّة لإزالة الالتباس، فالمثال التّالي سيسبب خطأ صيغة (SyntaxError) بسبب أنّ مفسّر اللّغة لن يعرف إلى من يجب إرسال المعامل الثالث argument3: | لكنّها ضروريّة لإزالة الالتباس، فالمثال التّالي سيسبب خطأ صيغة (SyntaxError) بسبب أنّ مفسّر اللّغة لن يعرف إلى من يجب إرسال المعامل الثالث argument3: | ||
<syntaxhighlight lang="ruby"> | |||
method_one argument1, method_two argument2, argument3 | method_one argument1, method_two argument2, argument3 | ||
</syntaxhighlight> | |||
إذا احتوى تعريف التابع على معامل مبدوء برمز *، فالمعاملات الموضعيّة الإضافيّة ستُسند إلى هذا المعامل في التابع على هيئة مصفوفة. | إذا احتوى تعريف التابع على معامل مبدوء برمز *، فالمعاملات الموضعيّة الإضافيّة ستُسند إلى هذا المعامل في التابع على هيئة مصفوفة. | ||
إذا لم يحتوِ تعريف التابع على معاملات قيم مفتاحية فإنّ أيّة معاملات قيم مفتاحية أو معاملات مصنِّفات ستُسند جميعها كمصنِف واحد إلى آخر معامل في تعريف التابع: | إذا لم يحتوِ تعريف التابع على معاملات قيم مفتاحية فإنّ أيّة معاملات قيم مفتاحية أو معاملات مصنِّفات ستُسند جميعها كمصنِف واحد إلى آخر معامل في تعريف التابع: | ||
<syntaxhighlight lang="ruby"> | |||
def my_method(options) | def my_method(options) | ||
p options | p options | ||
end | end | ||
my_method('a' => 1, b: 2) # تطبع: {'a'=>1, :b=>2} | my_method('a' => 1, b: 2) # تطبع: {'a'=>1, :b=>2} | ||
</syntaxhighlight> | |||
إذا مُرر عدد كبير من المعاملات الموضعية فسيسبب ذلك ظهور خطأ معاملات (ArgumentError). | إذا مُرر عدد كبير من المعاملات الموضعية فسيسبب ذلك ظهور خطأ معاملات (ArgumentError). | ||
سطر 74: | سطر 71: | ||
ففي أبسط الحالات عندما تكون المعاملات الافتراضية هي الأخيرة في أقصى اليمين: | ففي أبسط الحالات عندما تكون المعاملات الافتراضية هي الأخيرة في أقصى اليمين: | ||
<syntaxhighlight lang="ruby"> | |||
def my_method(a, b, c = 3, d = 4) | def my_method(a, b, c = 3, d = 4) | ||
p [a, b, c, d] | p [a, b, c, d] | ||
end | end | ||
</syntaxhighlight> | |||
لكلّ من المعاملين c و d قيمة افتراضية، فإذا مرّرت معاملين فقط في استدعاء التابع: | لكلّ من المعاملين c و d قيمة افتراضية، فإذا مرّرت معاملين فقط في استدعاء التابع: | ||
<syntaxhighlight lang="ruby"> | |||
my_method(1, 2) | my_method(1, 2) | ||
</syntaxhighlight> | |||
فستكون النتيجة كالتالي: | فستكون النتيجة كالتالي: | ||
<syntaxhighlight lang="text"> | |||
[1, 2, 3, 4] | [1, 2, 3, 4] | ||
</syntaxhighlight> | |||
وإذا مرّرت ثلاثة معاملات: | وإذا مرّرت ثلاثة معاملات: | ||
<syntaxhighlight lang="ruby"> | |||
my_method(1, 2, 5) | my_method(1, 2, 5) | ||
</syntaxhighlight> | |||
فستكون النتيجة | فستكون النتيجة | ||
<syntaxhighlight lang="text"> | |||
[1, 2, 5, 4] | [1, 2, 5, 4] | ||
</syntaxhighlight> | |||
حيث يملأ مفسّر اللّغة المعاملات النّاقصة من اليسار إلى اليمين. | حيث يملأ مفسّر اللّغة المعاملات النّاقصة من اليسار إلى اليمين. | ||
تسمح لغة روبي بأن توضع المعاملات الافتراضية في المنتصف بين المعاملات الموضعية الأخرى. لنأخذ هذا المثال الأكثر تعقيدًا: | تسمح لغة روبي بأن توضع المعاملات الافتراضية في المنتصف بين المعاملات الموضعية الأخرى. لنأخذ هذا المثال الأكثر تعقيدًا: | ||
<syntaxhighlight lang="ruby"> | |||
def my_method(a, b = 2, c = 3, d) | def my_method(a, b = 2, c = 3, d) | ||
p [a, b, c, d] | p [a, b, c, d] | ||
end | end | ||
</syntaxhighlight> | |||
هنا b و c يأخذان قيمًا افتراضيّة. فإذا مرّرت معاملين فقط في استدعاء التابع: | هنا b و c يأخذان قيمًا افتراضيّة. فإذا مرّرت معاملين فقط في استدعاء التابع: | ||
<syntaxhighlight lang="ruby"> | |||
my_method(1, 4) | my_method(1, 4) | ||
</syntaxhighlight> | |||
ستكون النتيجة: | ستكون النتيجة: | ||
<syntaxhighlight lang="text"> | |||
[1, 2, 3, 4] | [1, 2, 3, 4] | ||
</syntaxhighlight> | |||
وإذا مررت ثلاثة معاملات: | وإذا مررت ثلاثة معاملات: | ||
<syntaxhighlight lang="ruby"> | |||
my_method(1, 5, 6) | my_method(1, 5, 6) | ||
</syntaxhighlight> | |||
ستكون النتيجة: | ستكون النتيجة: | ||
<syntaxhighlight lang="text"> | |||
[1, 5, 3, 6] | [1, 5, 3, 6] | ||
</syntaxhighlight> | |||
من الصّعب وصف الذي يحصل هنا بالكلمات، لذلك سنشرحها باستخدام المتغيّرات وقيمها. | من الصّعب وصف الذي يحصل هنا بالكلمات، لذلك سنشرحها باستخدام المتغيّرات وقيمها. | ||
بداية تُسند القيمة 1 إلى a، ثمّ تسند القيمة 6 إلى d. وهكذا يبقى المعاملَين ذوَي القيمة الافتراضية. وطالما أنّ القيمة 5 لم تُسند بعد فستعطى إلى b، ويحصل c على القيمة الافتراضية 3. | بداية تُسند القيمة 1 إلى a، ثمّ تسند القيمة 6 إلى d. وهكذا يبقى المعاملَين ذوَي القيمة الافتراضية. وطالما أنّ القيمة 5 لم تُسند بعد فستعطى إلى b، ويحصل c على القيمة الافتراضية 3. | ||
== معاملات القيم المفتاحية == | == معاملات القيم المفتاحية == | ||
معاملات القيم المفتاحية تلي المعاملات الموضعية ويفصل بينها فواصل: | معاملات القيم المفتاحية تلي المعاملات الموضعية ويفصل بينها فواصل: | ||
<syntaxhighlight lang="ruby"> | |||
my_method(positional1, keyword1: value1, keyword2: value2) | my_method(positional1, keyword1: value1, keyword2: value2) | ||
</syntaxhighlight> | |||
إذا لم تظهر معاملات القيم المفتاحيّة عند استدعاء التابع رغم وجودها في تعريفه فستأخذ القيمة الافتراضيّة المعرّفة فيه. أمّا إذا مُرّرت هذه المعاملات في الاستدعاء دون أن يحتوي عليها تعريف التّابع فسيظهر حينئذ خطأ معاملات (ArgumentError). | إذا لم تظهر معاملات القيم المفتاحيّة عند استدعاء التابع رغم وجودها في تعريفه فستأخذ القيمة الافتراضيّة المعرّفة فيه. أمّا إذا مُرّرت هذه المعاملات في الاستدعاء دون أن يحتوي عليها تعريف التّابع فسيظهر حينئذ خطأ معاملات (ArgumentError). | ||
== معاملات الكتل البرمجية == | == معاملات الكتل البرمجية == | ||
معاملات الكتل البرمجيّة تمرّر كتلة برمجيّة من النّطاق الذي يستدعي التّابع، ويكون ترتيب هذه المعاملات دائمًا في نهاية المعاملات الممرّرة للتابع. وتُمرّر الكتلة البرمجيّة باستخدام do.. end أو الأقواس {..}: | معاملات الكتل البرمجيّة تمرّر كتلة برمجيّة من النّطاق الذي يستدعي التّابع، ويكون ترتيب هذه المعاملات دائمًا في نهاية المعاملات الممرّرة للتابع. وتُمرّر الكتلة البرمجيّة باستخدام do.. end أو الأقواس {..}: | ||
<syntaxhighlight lang="ruby"> | |||
my_method do | my_method do | ||
# ... | # ... | ||
end | end | ||
</syntaxhighlight> | |||
أو: | أو: | ||
<syntaxhighlight lang="ruby"> | |||
my_method { | my_method { | ||
# ... | # ... | ||
} | } | ||
</syntaxhighlight> | |||
تأخذ do-end أولويّة أدنى من {}، ففي المثال التّالي: | تأخذ do-end أولويّة أدنى من {}، ففي المثال التّالي: | ||
<syntaxhighlight lang="ruby"> | |||
method_1 method_2 { | method_1 method_2 { | ||
# ... | # ... | ||
} | } | ||
</syntaxhighlight> | |||
تُرسل الكتلة البرمجيّة إلى التابع method_2، بينما في المثال: | تُرسل الكتلة البرمجيّة إلى التابع method_2، بينما في المثال: | ||
<syntaxhighlight lang="ruby"> | |||
method_1 method_2 do | method_1 method_2 do | ||
# ... | # ... | ||
end | end | ||
</syntaxhighlight> | |||
ترسل الكتلة إلى التابع method_1. لاحظ أنّه في حال استخدمت الأقواس {} في الحالة الأولى فسترسل الكتلة إلى التابع الأول method_1. | ترسل الكتلة إلى التابع method_1. لاحظ أنّه في حال استخدمت الأقواس {} في الحالة الأولى فسترسل الكتلة إلى التابع الأول method_1. | ||
يمكن أن تستقبل الكتلة البرمجية معاملات من التابع المرسلة له. هذه المعاملات تعرّف بطريقة مشابهة لطريقة تعريفها في التوابع، وتمرّر ضمن |...| بعد كلمة do أو القوس المفتتح للكتلة: | يمكن أن تستقبل الكتلة البرمجية معاملات من التابع المرسلة له. هذه المعاملات تعرّف بطريقة مشابهة لطريقة تعريفها في التوابع، وتمرّر ضمن |...| بعد كلمة do أو القوس المفتتح للكتلة: | ||
<syntaxhighlight lang="ruby"> | |||
my_method do |argument1, argument2| | my_method do |argument1, argument2| | ||
# ... | # ... | ||
end | end | ||
</syntaxhighlight> | |||
== المعاملات المحليّة للكتلة البرمجيّة == | == المعاملات المحليّة للكتلة البرمجيّة == | ||
يمكنك أيضًا تعريف معاملات محليّة على مستوى الكتلة البرمجيّة باستخدام الرّمز ; في قائمة معاملات الكتلة. لاحظ أنّ إسناد قيم إلى هذه المعاملات ليس له أيّ تأثير على المتغيّرات المحليّة التي لها نفس الاسم والموجودة خارج هذه الكتلة في النطاق الذي يستدعي التابع: | يمكنك أيضًا تعريف معاملات محليّة على مستوى الكتلة البرمجيّة باستخدام الرّمز ; في قائمة معاملات الكتلة. لاحظ أنّ إسناد قيم إلى هذه المعاملات ليس له أيّ تأثير على المتغيّرات المحليّة التي لها نفس الاسم والموجودة خارج هذه الكتلة في النطاق الذي يستدعي التابع: | ||
<syntaxhighlight lang="ruby"> | |||
def my_method | def my_method | ||
yield self | yield self | ||
end | end | ||
place = "world" | place = "world" | ||
my_method do |obj; place| | my_method do |obj; place| | ||
place = "block" | place = "block" | ||
puts "hello #{obj} this is #{place}" | puts "hello #{obj} this is #{place}" | ||
end | end | ||
puts "place is: #{place}" | puts "place is: #{place}" | ||
</syntaxhighlight> | |||
وتكون النتيجة: | وتكون النتيجة: | ||
<syntaxhighlight lang="text"> | |||
hello main this is block | hello main this is block | ||
place is world | place is world | ||
</syntaxhighlight> | |||
فالمتغيّر place ضمن الكتلة الممرّرة إلى التابع ليس نفسه المتغيّر place خارجها، وبالمقابل لو حذفنا ;place من معاملات الكتلة ستكون النتيجة: | فالمتغيّر place ضمن الكتلة الممرّرة إلى التابع ليس نفسه المتغيّر place خارجها، وبالمقابل لو حذفنا ;place من معاملات الكتلة ستكون النتيجة: | ||
<syntaxhighlight lang="text"> | |||
hello main this is block | hello main this is block | ||
place is block | place is block | ||
</syntaxhighlight> | |||
== التحويل من مصفوفة إلى معاملات == | == التحويل من مصفوفة إلى معاملات == | ||
ليكن لدينا هذا التابع: | ليكن لدينا هذا التابع: | ||
<syntaxhighlight lang="ruby"> | |||
def my_method(argument1, argument2, argument3) | def my_method(argument1, argument2, argument3) | ||
end | end | ||
</syntaxhighlight> | |||
يمكنك تحويل مصفوفة إلى سلسلة من المعاملات عن طريق تمرير المصفوفة مسبوقة برمز النجمة * أو المسمى بمعامل الفصل: | يمكنك تحويل مصفوفة إلى سلسلة من المعاملات عن طريق تمرير المصفوفة مسبوقة برمز النجمة * أو المسمى بمعامل الفصل: | ||
<syntaxhighlight lang="ruby"> | |||
arguments = [1, 2, 3] | arguments = [1, 2, 3] | ||
my_method(*arguments) | my_method(*arguments) | ||
</syntaxhighlight> | |||
أو: | أو: | ||
<syntaxhighlight lang="ruby"> | |||
arguments = [2, 3] | arguments = [2, 3] | ||
my_method(1, *arguments) | my_method(1, *arguments) | ||
</syntaxhighlight> | |||
كلاهما مكافئ لما يلي: | كلاهما مكافئ لما يلي: | ||
<syntaxhighlight lang="ruby"> | |||
my_method(1, 2, 3) | my_method(1, 2, 3) | ||
</syntaxhighlight> | |||
في حالة أنّ التابع يستقبل معاملات القيم المفتاحية فاستخدام معامل الفصل حينها سيحوّل المصنّف الموجود في نهاية المصفوفة إلى معاملات قيم مفتاحية: | في حالة أنّ التابع يستقبل معاملات القيم المفتاحية فاستخدام معامل الفصل حينها سيحوّل المصنّف الموجود في نهاية المصفوفة إلى معاملات قيم مفتاحية: | ||
<syntaxhighlight lang="ruby"> | |||
def my_method(a, b, c: 3) | def my_method(a, b, c: 3) | ||
end | end | ||
arguments = [1, 2, { c: 4 }] | arguments = [1, 2, { c: 4 }] | ||
my_method(*arguments) | my_method(*arguments) | ||
</syntaxhighlight> | |||
يمكنك أيضًا استخدام الرمز ** (سيأتي شرحه لاحقًا) لتحوّل مصنّفًا إلى معامل قيم مفتاحية. | يمكنك أيضًا استخدام الرمز ** (سيأتي شرحه لاحقًا) لتحوّل مصنّفًا إلى معامل قيم مفتاحية. | ||
إذا لم يطابق عددُ الكائنات في المصفوفة عددَ المعاملات في التابع فسيظهر خطأ معاملات (ArgumentError). | إذا لم يطابق عددُ الكائنات في المصفوفة عددَ المعاملات في التابع فسيظهر خطأ معاملات (ArgumentError). | ||
وإذا جاء معامل الفصل في بداية المعاملات عند الاستدعاء، فيجب استخدام الأقواس عندها منعًا لظهور تحذير (warning). | وإذا جاء معامل الفصل في بداية المعاملات عند الاستدعاء، فيجب استخدام الأقواس عندها منعًا لظهور تحذير (warning). | ||
== التحويل من تصنيف إلى معامل قيم مفتاحية == | == التحويل من تصنيف إلى معامل قيم مفتاحية == | ||
لنأخذ هذا التابع على سبيل المثال: | لنأخذ هذا التابع على سبيل المثال: | ||
<syntaxhighlight lang="ruby"> | |||
def my_method(first: 1, second: 2, third: 3) | def my_method(first: 1, second: 2, third: 3) | ||
end | end | ||
</syntaxhighlight> | |||
يمكنك تحويل المصنّف إلى معاملات قيم مفتاحية باستخدام المعامل **: | يمكنك تحويل المصنّف إلى معاملات قيم مفتاحية باستخدام المعامل **: | ||
<syntaxhighlight lang="ruby"> | |||
arguments = { first: 3, second: 4, third: 5 } | arguments = { first: 3, second: 4, third: 5 } | ||
my_method(**arguments) | my_method(**arguments) | ||
</syntaxhighlight> | |||
أو: | أو: | ||
<syntaxhighlight lang="ruby"> | |||
arguments = { first: 3, second: 4 } | arguments = { first: 3, second: 4 } | ||
my_method(third: 5, **arguments) | my_method(third: 5, **arguments) | ||
</syntaxhighlight> | |||
كلاهما مكافئ لما يلي: | كلاهما مكافئ لما يلي: | ||
<syntaxhighlight lang="ruby"> | |||
my_method(first: 3, second: 4, third: 5) | my_method(first: 3, second: 4, third: 5) | ||
</syntaxhighlight> | |||
استخدم ** في تعريف التابع لتجمّع معاملات القيم المفتاحيّة أيًا كانت، إذ أنّها لن تُجمّع باستخدام *: | استخدم ** في تعريف التابع لتجمّع معاملات القيم المفتاحيّة أيًا كانت، إذ أنّها لن تُجمّع باستخدام *: | ||
<syntaxhighlight lang="ruby"> | |||
def my_method(*a, **kw) | def my_method(*a, **kw) | ||
p arguments: a, keywords: kw | p arguments: a, keywords: kw | ||
end | end | ||
my_method(1, 2, '3' => 4, five: 6) | my_method(1, 2, '3' => 4, five: 6) | ||
</syntaxhighlight> | |||
وتكون النتيجة: | وتكون النتيجة: | ||
<syntaxhighlight lang="text"> | |||
< | {:arguments=>[1, 2, {"3"=>4}], :keywords=>{:five=>6}} | ||
</syntaxhighlight> | |||
على عكس معامل الفصل الموضّح سابقًا فإنّ المعامل ** ليس له اسم معيّن متعارف عليه. | على عكس معامل الفصل الموضّح سابقًا فإنّ المعامل ** ليس له اسم معيّن متعارف عليه. | ||
== التحويل من كائنات Proc إلى كتل برمجيّة == | == التحويل من كائنات Proc إلى كتل برمجيّة == | ||
لنأخذ التابع التالي على سبيل المثال: | لنأخذ التابع التالي على سبيل المثال: | ||
<syntaxhighlight lang="ruby"> | |||
def my_method | def my_method | ||
yield self | yield self | ||
end | end | ||
</syntaxhighlight> | |||
يمكنك تحويل كائن من نوع proc أو lambda إلى كتلة برمجيّة باستخدام المعامل &: | يمكنك تحويل كائن من نوع proc أو lambda إلى كتلة برمجيّة باستخدام المعامل &: | ||
<syntaxhighlight lang="ruby"> | |||
argument = proc { |a| puts "#{a.inspect} was yielded" } | argument = proc { |a| puts "#{a.inspect} was yielded" } | ||
my_method(&argument) | my_method(&argument) | ||
</syntaxhighlight> | |||
إذا سبق في الاستدعاء معامل الفصل * فيجب حينها استخدام الاقواس منعًا لظهور تحذير. | إذا سبق في الاستدعاء معامل الفصل * فيجب حينها استخدام الاقواس منعًا لظهور تحذير. | ||
وكما هو الحال بالنّسبة للمعامل ** فإنّ المعامل & أيضًا ليس له اسم معيّن متعارف عليه. | وكما هو الحال بالنّسبة للمعامل ** فإنّ المعامل & أيضًا ليس له اسم معيّن متعارف عليه. | ||
== البحث عن التوابع == | == البحث عن التوابع == | ||
عندما ترسل رسالة فإنّ مفسر اللغة يبحث عن التابع الذي يطابق اسم مستقبل الرسالة، هذه التّوابع محزّنة في أصناف (classes) ووحدات (modules) يمرّ المفسّر عليها أثناء عمليّة البحث، ولا يبحث في كائناتها. | عندما ترسل رسالة فإنّ مفسر اللغة يبحث عن التابع الذي يطابق اسم مستقبل الرسالة، هذه التّوابع محزّنة في أصناف (classes) ووحدات (modules) يمرّ المفسّر عليها أثناء عمليّة البحث، ولا يبحث في كائناتها. | ||
هذا هو الترتيب المتّبع في عمليّة البحث عن التابع للصنف أو الوحدة R الخاصّ بالمستقبل: | هذا هو الترتيب المتّبع في عمليّة البحث عن التابع للصنف أو الوحدة R الخاصّ بالمستقبل: | ||
* وحدات R السابقة بترتيب عكسيّ. | * وحدات R السابقة بترتيب عكسيّ. | ||
سطر 319: | سطر 261: | ||
* الوحدات المتضمّنة في R بترتيب عكسيّ | * الوحدات المتضمّنة في R بترتيب عكسيّ | ||
وإذا كان للصنفّ R صنف أب (superclass) فستكرّر العمليّة في الصنف الأب حتى يُعثر على التابع، وتتوقّف عمليّة البحث متى عُثر على التابع. | وإذا كان للصنفّ R صنف أب (superclass) فستكرّر العمليّة في الصنف الأب حتى يُعثر على التابع، وتتوقّف عمليّة البحث متى عُثر على التابع. | ||
وإذا لم يُعثر على أيّ نتيجة فستعاد العمليّة من البداية لكن بالبحث عن method_missing، والتابع الافتراضيّ له BasicObject#method_missing والذي يسبّب ظهور خطأ اسم (NameError) عندما يستدعى. | وإذا لم يُعثر على أيّ نتيجة فستعاد العمليّة من البداية لكن بالبحث عن method_missing، والتابع الافتراضيّ له BasicObject#method_missing والذي يسبّب ظهور خطأ اسم (NameError) عندما يستدعى. | ||
عند تفعيل ميزة التحسينات الاختبارية فسيتغيّر ترتيب البحث عن التوابع، اقرأ توثيق التحسينات لمزيد من التفاصيل. | عند تفعيل ميزة التحسينات الاختبارية فسيتغيّر ترتيب البحث عن التوابع، اقرأ توثيق التحسينات لمزيد من التفاصيل. | ||
== مصادر == | == مصادر == | ||
* [https://ruby-doc.org/core-2.5.1/doc/syntax/calling_methods_rdoc.html صفحة Calling Methods في توثيق روبي الرسمي.] | * [https://ruby-doc.org/core-2.5.1/doc/syntax/calling_methods_rdoc.html صفحة Calling Methods في توثيق روبي الرسمي.] |
مراجعة 21:53، 15 نوفمبر 2018
استدعاء التوابع في لغة روبي
عندما تستدعي تابعًا، فإنّك تمرّر رسالة لكائن معيّن لأجل تنفيذ مهمّة معيّنة، ويتمّ ذلك في لغة روبي كالتّالي:
my_method()
لاحظ أنّ استخدام الأقواس المنحنية هنا اختياريّ:
my_method
المعتمد في هذا التّوثيق أن تُستخدّم الأقواس عند وجود المعامِلات لإزالة الالتباس، إلا في حالة وجود فرق بين وجود الأقواس وحذفها.
هذا القسم يغطّي فقط كيفيّة استدعاء التوابع، وستُشرَح كيفيّة تعريف التّوابع في قسم آخر.
المستقبِل
المستقبِل الافتراضي في لغة روبي هو self وهو الذي يُستخدَم في حال عدم تحديد أيّ مستقبل آخر. ولأجل تحديد مستقبِل يستَدعى التابع بالشّكل التالي:
my_object.my_method
في هذه الحالة تُرسل رسالة my_method إلى الكائن my_object. فكلّ كائن يمكنه أن يكون مستقبِلًا لتابع ما، لكن حتى يتمّ ذلك يجب أن يكون التابع مرئيّ لهذا الكائن، وإلّا فسيظهر خطأ من نوع NoMethodError.
يمكنك استخدام & متبوعة بنقطة لتعيّن & كمستقبل، حينها لن يُنفّذ التابع، وستكون النتيجة nil عندما يكون المستقبِل nil، ولن تُقيَّم معامِلات التّابع.
كما يمكنك استخدام :: لتعيين المستقبل، لكنّ هذه الطريقة نادرة الاستخدام لأنّها قد تسبّب التباسًا مع الرمز :: المستخدم في مجالات الأسماء (namespaces).
المعاملات
تدعم لغة روبي ثلاثة أنواع من المعامِلات التي يمكن تمريرها عند إرسال الرسائل وهي: المعاملات الموضعية، معاملات القيم المفتاحية (أو ذات الاسم)، ومعاملات الكتلة البرمجية. كل رسالة تُرسَل تستخدم نوعًا أو اثنين أو كل هذه الأنواع، إلّا أنّها إذا استُخدمت معًا فيجب أن تكون ضمن هذا الترتيب نفسه.
كلّ المعاملات في لغة روبي تُمرّر مرجعيًا ولا يؤجّل تقييمها. وكلّ معامل يُكتب متبوعًا بفاصلة , كالتّالي:
my_method(1, '2', :three)
يُمكن أن تكون المعاملات على شكل تعبير برمجي كالمصنِّفات (Hashes):
'key' => value
أو معاملات القيم المفتاحية (Keyword arguments):
key: value
المصنِّفات ومعاملات القيم المفتاحية يجب أن تكون متجاورة ويجب أن تتلو المعاملات الموضعيّة، ولا بأس في أن تُخلط فيما بينها:
my_method('a' => 1, b: 2, 'c' => 3)
المعاملات الموضعيّة
المعاملات الموضعيّة للرسالة تتبع اسم التابع مباشرة:
my_method(argument1, argument2)
في كثير من الحالات لا تكون الأقواس ضروريّة عند إرسال الرسالة:
my_method argument1, argument2
لكنّها ضروريّة لإزالة الالتباس، فالمثال التّالي سيسبب خطأ صيغة (SyntaxError) بسبب أنّ مفسّر اللّغة لن يعرف إلى من يجب إرسال المعامل الثالث argument3:
method_one argument1, method_two argument2, argument3
إذا احتوى تعريف التابع على معامل مبدوء برمز *، فالمعاملات الموضعيّة الإضافيّة ستُسند إلى هذا المعامل في التابع على هيئة مصفوفة.
إذا لم يحتوِ تعريف التابع على معاملات قيم مفتاحية فإنّ أيّة معاملات قيم مفتاحية أو معاملات مصنِّفات ستُسند جميعها كمصنِف واحد إلى آخر معامل في تعريف التابع:
def my_method(options)
p options
end
my_method('a' => 1, b: 2) # تطبع: {'a'=>1, :b=>2}
إذا مُرر عدد كبير من المعاملات الموضعية فسيسبب ذلك ظهور خطأ معاملات (ArgumentError).
المعاملات الموضعية الافتراضية
عندما تعرَّف معاملات افتراضية في تعريف التابع فلست بحاجة إلى تزويده بكل المعاملات عند الاستدعاء، فالمفسّر سيملأ المعاملات الناقصة وفق الترتيب.
ففي أبسط الحالات عندما تكون المعاملات الافتراضية هي الأخيرة في أقصى اليمين:
def my_method(a, b, c = 3, d = 4)
p [a, b, c, d]
end
لكلّ من المعاملين c و d قيمة افتراضية، فإذا مرّرت معاملين فقط في استدعاء التابع:
my_method(1, 2)
فستكون النتيجة كالتالي:
[1, 2, 3, 4]
وإذا مرّرت ثلاثة معاملات:
my_method(1, 2, 5)
فستكون النتيجة
[1, 2, 5, 4]
حيث يملأ مفسّر اللّغة المعاملات النّاقصة من اليسار إلى اليمين. تسمح لغة روبي بأن توضع المعاملات الافتراضية في المنتصف بين المعاملات الموضعية الأخرى. لنأخذ هذا المثال الأكثر تعقيدًا:
def my_method(a, b = 2, c = 3, d)
p [a, b, c, d]
end
هنا b و c يأخذان قيمًا افتراضيّة. فإذا مرّرت معاملين فقط في استدعاء التابع:
my_method(1, 4)
ستكون النتيجة:
[1, 2, 3, 4]
وإذا مررت ثلاثة معاملات:
my_method(1, 5, 6)
ستكون النتيجة:
[1, 5, 3, 6]
من الصّعب وصف الذي يحصل هنا بالكلمات، لذلك سنشرحها باستخدام المتغيّرات وقيمها. بداية تُسند القيمة 1 إلى a، ثمّ تسند القيمة 6 إلى d. وهكذا يبقى المعاملَين ذوَي القيمة الافتراضية. وطالما أنّ القيمة 5 لم تُسند بعد فستعطى إلى b، ويحصل c على القيمة الافتراضية 3.
معاملات القيم المفتاحية
معاملات القيم المفتاحية تلي المعاملات الموضعية ويفصل بينها فواصل:
my_method(positional1, keyword1: value1, keyword2: value2)
إذا لم تظهر معاملات القيم المفتاحيّة عند استدعاء التابع رغم وجودها في تعريفه فستأخذ القيمة الافتراضيّة المعرّفة فيه. أمّا إذا مُرّرت هذه المعاملات في الاستدعاء دون أن يحتوي عليها تعريف التّابع فسيظهر حينئذ خطأ معاملات (ArgumentError).
معاملات الكتل البرمجية
معاملات الكتل البرمجيّة تمرّر كتلة برمجيّة من النّطاق الذي يستدعي التّابع، ويكون ترتيب هذه المعاملات دائمًا في نهاية المعاملات الممرّرة للتابع. وتُمرّر الكتلة البرمجيّة باستخدام do.. end أو الأقواس {..}:
my_method do
# ...
end
أو:
my_method {
# ...
}
تأخذ do-end أولويّة أدنى من {}، ففي المثال التّالي:
method_1 method_2 {
# ...
}
تُرسل الكتلة البرمجيّة إلى التابع method_2، بينما في المثال:
method_1 method_2 do
# ...
end
ترسل الكتلة إلى التابع method_1. لاحظ أنّه في حال استخدمت الأقواس {} في الحالة الأولى فسترسل الكتلة إلى التابع الأول method_1. يمكن أن تستقبل الكتلة البرمجية معاملات من التابع المرسلة له. هذه المعاملات تعرّف بطريقة مشابهة لطريقة تعريفها في التوابع، وتمرّر ضمن |...| بعد كلمة do أو القوس المفتتح للكتلة:
my_method do |argument1, argument2|
# ...
end
المعاملات المحليّة للكتلة البرمجيّة
يمكنك أيضًا تعريف معاملات محليّة على مستوى الكتلة البرمجيّة باستخدام الرّمز ; في قائمة معاملات الكتلة. لاحظ أنّ إسناد قيم إلى هذه المعاملات ليس له أيّ تأثير على المتغيّرات المحليّة التي لها نفس الاسم والموجودة خارج هذه الكتلة في النطاق الذي يستدعي التابع:
def my_method
yield self
end
place = "world"
my_method do |obj; place|
place = "block"
puts "hello #{obj} this is #{place}"
end
puts "place is: #{place}"
وتكون النتيجة:
hello main this is block
place is world
فالمتغيّر place ضمن الكتلة الممرّرة إلى التابع ليس نفسه المتغيّر place خارجها، وبالمقابل لو حذفنا ;place من معاملات الكتلة ستكون النتيجة:
hello main this is block
place is block
التحويل من مصفوفة إلى معاملات
ليكن لدينا هذا التابع:
def my_method(argument1, argument2, argument3)
end
يمكنك تحويل مصفوفة إلى سلسلة من المعاملات عن طريق تمرير المصفوفة مسبوقة برمز النجمة * أو المسمى بمعامل الفصل:
arguments = [1, 2, 3]
my_method(*arguments)
أو:
arguments = [2, 3]
my_method(1, *arguments)
كلاهما مكافئ لما يلي:
my_method(1, 2, 3)
في حالة أنّ التابع يستقبل معاملات القيم المفتاحية فاستخدام معامل الفصل حينها سيحوّل المصنّف الموجود في نهاية المصفوفة إلى معاملات قيم مفتاحية:
def my_method(a, b, c: 3)
end
arguments = [1, 2, { c: 4 }]
my_method(*arguments)
يمكنك أيضًا استخدام الرمز ** (سيأتي شرحه لاحقًا) لتحوّل مصنّفًا إلى معامل قيم مفتاحية. إذا لم يطابق عددُ الكائنات في المصفوفة عددَ المعاملات في التابع فسيظهر خطأ معاملات (ArgumentError). وإذا جاء معامل الفصل في بداية المعاملات عند الاستدعاء، فيجب استخدام الأقواس عندها منعًا لظهور تحذير (warning).
التحويل من تصنيف إلى معامل قيم مفتاحية
لنأخذ هذا التابع على سبيل المثال:
def my_method(first: 1, second: 2, third: 3)
end
يمكنك تحويل المصنّف إلى معاملات قيم مفتاحية باستخدام المعامل **:
arguments = { first: 3, second: 4, third: 5 }
my_method(**arguments)
أو:
arguments = { first: 3, second: 4 }
my_method(third: 5, **arguments)
كلاهما مكافئ لما يلي:
my_method(first: 3, second: 4, third: 5)
استخدم ** في تعريف التابع لتجمّع معاملات القيم المفتاحيّة أيًا كانت، إذ أنّها لن تُجمّع باستخدام *:
def my_method(*a, **kw)
p arguments: a, keywords: kw
end
my_method(1, 2, '3' => 4, five: 6)
وتكون النتيجة:
{:arguments=>[1, 2, {"3"=>4}], :keywords=>{:five=>6}}
على عكس معامل الفصل الموضّح سابقًا فإنّ المعامل ** ليس له اسم معيّن متعارف عليه.
التحويل من كائنات Proc إلى كتل برمجيّة
لنأخذ التابع التالي على سبيل المثال:
def my_method
yield self
end
يمكنك تحويل كائن من نوع proc أو lambda إلى كتلة برمجيّة باستخدام المعامل &:
argument = proc { |a| puts "#{a.inspect} was yielded" }
my_method(&argument)
إذا سبق في الاستدعاء معامل الفصل * فيجب حينها استخدام الاقواس منعًا لظهور تحذير. وكما هو الحال بالنّسبة للمعامل ** فإنّ المعامل & أيضًا ليس له اسم معيّن متعارف عليه.
البحث عن التوابع
عندما ترسل رسالة فإنّ مفسر اللغة يبحث عن التابع الذي يطابق اسم مستقبل الرسالة، هذه التّوابع محزّنة في أصناف (classes) ووحدات (modules) يمرّ المفسّر عليها أثناء عمليّة البحث، ولا يبحث في كائناتها. هذا هو الترتيب المتّبع في عمليّة البحث عن التابع للصنف أو الوحدة R الخاصّ بالمستقبل:
- وحدات R السابقة بترتيب عكسيّ.
- تابع مطابق في R
- الوحدات المتضمّنة في R بترتيب عكسيّ
وإذا كان للصنفّ R صنف أب (superclass) فستكرّر العمليّة في الصنف الأب حتى يُعثر على التابع، وتتوقّف عمليّة البحث متى عُثر على التابع. وإذا لم يُعثر على أيّ نتيجة فستعاد العمليّة من البداية لكن بالبحث عن method_missing، والتابع الافتراضيّ له BasicObject#method_missing والذي يسبّب ظهور خطأ اسم (NameError) عندما يستدعى. عند تفعيل ميزة التحسينات الاختبارية فسيتغيّر ترتيب البحث عن التوابع، اقرأ توثيق التحسينات لمزيد من التفاصيل.