الفرق بين المراجعتين لصفحة: «Ruby/modules and classes»
لا ملخص تعديل |
جميل-بيلوني (نقاش | مساهمات) طلا ملخص تعديل |
||
(1 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة) | |||
سطر 1: | سطر 1: | ||
= الوحدات = | <noinclude>{{DISPLAYTITLE:الوحدات والأصناف في روبي}}</noinclude> | ||
تخدم الوحدات غايتين اثنتين في لغة روبي وهما نطاقات | ==الوحدات== | ||
يستخدم نطاق الأسماء | تخدم الوحدات (Modules) غايتين اثنتين في لغة روبي وهما: ميّزة نطاقات الأسماء (namespace)، والخلط الضمني (mix-in) التي سنوضّحها لاحقًا. | ||
وظيفة الخلط الضمني Mix-in تسمح بمشاركة توابع مشتركة عبر عدد من الأصناف أو | |||
يستخدم نطاق الأسماء لتنظيم الشيفرة البرمجية ضمن مجموعات مستقلّة تمنع تداخل التوابع والمتغيّرات ذات الأسماء المتشابهة فيما بينها. فعلى سبيل المثال، نطاق الأسماء IRB يوفّر عمليات irb والتي تمنع التصادم مع الاسم الشائع "Context". | |||
وظيفة الخلط الضمني (Mix-in) تسمح بمشاركة توابع مشتركة عبر عدد من الأصناف أو الوحدات، إذ يأتي مع لغة روبي على سبيل المثال الوحدة <code>[[Ruby/Enumerable|Enumerable]]</code> التي توفّر توابع حساب (enumeration) مبنية على التابع <code>each</code>. كما تسمح الوحدة <code>[[Ruby/Comparable|Comparable]]</code> بموازنة الكائنات بناء على تابع الموازنة <code><=></code>. | |||
لاحظ وجود شبه كبير بين الوحدات والأصناف، بالإضافة إلى إمكانية الخلط الضمني داخل الوحدة، فوصف الوحدات أدناه يمكن تطبيقه كذلك على الأصناف. | لاحظ وجود شبه كبير بين الوحدات والأصناف، بالإضافة إلى إمكانية الخلط الضمني داخل الوحدة، فوصف الوحدات أدناه يمكن تطبيقه كذلك على الأصناف. | ||
== تعريف الوحدة == | ===تعريف الوحدة=== | ||
تُنشأ الوحدة باستخدام الكلمة المحجوزة module: | تُنشأ الوحدة باستخدام الكلمة المحجوزة <code>module</code>:<syntaxhighlight lang="ruby"> | ||
<syntaxhighlight lang="ruby"> | |||
module MyModule | module MyModule | ||
# ... | # ... | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>يمكن إعادة فتح الوحدة عددًا غير محدود من المرات لإضافة أو تعديل أو حذف وظائف منها.<syntaxhighlight lang="ruby"> | ||
يمكن إعادة فتح الوحدة عددًا غير محدود من المرات لإضافة أو تعديل أو حذف وظائف منها. | |||
<syntaxhighlight lang="ruby"> | |||
module MyModule | module MyModule | ||
def my_method | def my_method | ||
سطر 23: | سطر 24: | ||
remove_method :my_method | remove_method :my_method | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>تُعدّ إعادة فتح الأصناف ميّزة فعّالة جدًا في لغة روبي، لكنّ الاستخدام الأمثل لها يكمن في إعادة فتح أصنافك الخاصّة، لأنّ فتح أصناف أخرى لا تمتلكها أنت قد يؤدي إلى تضاربات أو صعوبة في تتبع الأخطاء. | ||
تُعدّ إعادة فتح الأصناف ميّزة فعّالة جدًا في لغة روبي، لكنّ الاستخدام الأمثل لها يكمن في إعادة فتح أصنافك الخاصّة، لأنّ فتح أصناف أخرى لا تمتلكها أنت قد يؤدي إلى تضاربات أو صعوبة في تتبع الأخطاء. | ===التشعب=== | ||
== | يمكن تعريف الوحدات داخل بعضها بشكل متشعب (nested):<syntaxhighlight lang="ruby"> | ||
يمكن تعريف الوحدات داخل بعضها: | |||
<syntaxhighlight lang="ruby"> | |||
module Outer | module Outer | ||
module Inner | module Inner | ||
end | end | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>كثير من الحزم في لغة روبي تعرّف وحدةً أو صنفًا خارجيًّا ليؤمّن نطاق أسماء خاصّ بالعمليات الخاصة بهذه الحزمة. | ||
كثير من الحزم في لغة روبي تعرّف | |||
كما بإمكانك تعريف الوحدات الضمنية باستخدام :: على أن يكون الصنف أو الوحدة الكبرى معرّفة مسبقًا: | كما بإمكانك تعريف الوحدات الضمنية باستخدام <code>::</code> على أن يكون الصنف أو الوحدة الكبرى معرّفة مسبقًا:<syntaxhighlight lang="ruby"> | ||
<syntaxhighlight lang="ruby"> | |||
module Outer::Inner::GrandChild | module Outer::Inner::GrandChild | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>لاحظ أنّ هذا المثال سيسبب الخطأ <code>[[Ruby/NameError|NameError]]</code> إذا لم تكن الوحدة <code>Outer</code> والوحدة الضمنية <code>Outer::Inner</code> معرفتان. | ||
لاحظ أنّ هذا المثال سيسبب | |||
هذا الأسلوب يفيد المؤلّف في تخفيض عدد المسافات البادئة للشيفرة البرمجية من ثلاثة مستويات إلى مستوى واحد. إلا أنّ نطاق البحث عن المتغيّرات يختلف عند إنشاء نطاق أسماء باستخدام الصيغة الأساسية بدلًا من الصيغة المختصرة. | هذا الأسلوب يفيد المؤلّف في تخفيض عدد المسافات البادئة للشيفرة البرمجية من ثلاثة مستويات إلى مستوى واحد. إلا أنّ نطاق البحث عن المتغيّرات يختلف عند إنشاء نطاق أسماء باستخدام الصيغة الأساسية بدلًا من الصيغة المختصرة. | ||
== النطاق == | ===النطاق=== | ||
=== الكائن الذاتي self === | ====الكائن الذاتي <code>self</code>==== | ||
يشير self إلى الكائن الذي يعرّف النطاق الحاليّ، ويتغيّر هذا الكائن عند دخول تابع مختلف أو عند تعريف وحدة جديدة. | يشير <code>self</code> إلى الكائن الذي يعرّف النطاق الحاليّ، ويتغيّر هذا الكائن عند دخول تابع مختلف أو عند تعريف وحدة جديدة. | ||
=== الثوابت === | ====الثوابت==== | ||
الثوابت التي يمكن الوصول إليها تختلف تبعًا لصيغة التعريف الضمنيّ للوحدات. ففي المثال | الثوابت التي يمكن الوصول إليها تختلف تبعًا لصيغة التعريف الضمنيّ للوحدات. ففي المثال التالي، يعدّ الثابت <code>A::Z</code> قابلًا للوصول من <code>B</code> على فرض أنّ <code>A</code> هو جزء من عملية التضمين:<syntaxhighlight lang="ruby"> | ||
<syntaxhighlight lang="ruby"> | |||
module A | module A | ||
Z = 1 | Z = 1 | ||
سطر 54: | سطر 51: | ||
end | end | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>إلا أنّك إذا استخدمت الرمز <code>::</code> لتعريف الوحدة الضمنية <code>A::B</code> بدون كتابتها داخل الوحدة <code>A</code>، فسيظهر خطأ من النوع <code>[[Ruby/NameError|NameError]]</code> بسبب كون التضمين لا يحوي الوحدة <code>A</code>.<syntaxhighlight lang="ruby"> | ||
إلا أنّك إذا استخدمت الرمز :: لتعريف الوحدة الضمنية A::B بدون كتابتها داخل الوحدة | |||
<syntaxhighlight lang="ruby"> | |||
module A | module A | ||
Z = 1 | Z = 1 | ||
سطر 64: | سطر 59: | ||
p Z #=> يسبب NameError | p Z #=> يسبب NameError | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>وإذا عُرّف الثابت في نطاق خارج جميع الوحدات، فبإمكانك حينها كتابته مسبوقًا بالنقطتين <code>::</code> للإشارة إليه:<syntaxhighlight lang="ruby"> | ||
وإذا عُرّف الثابت في نطاق خارج جميع الوحدات، فبإمكانك حينها كتابته مسبوقًا | |||
<syntaxhighlight lang="ruby"> | |||
Z = 0 | Z = 0 | ||
module A | module A | ||
سطر 75: | سطر 68: | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== التوابع === | ====التوابع==== | ||
راجع صفحة التوثيق الخاصة بصيغة التوابع لتتعرف على صيغة تعريفها. | راجع صفحة التوثيق الخاصة بصيغة [[Ruby/methods|التوابع]] لتتعرف على صيغة تعريفها. | ||
يمكن استدعاء توابع الأصناف مباشرة، ولعلّك تجد ذلك غريبًا، لكنّ التابع الخاص بالوحدة يطلق عليه تابع الصنف بدلًا من تابع | |||
عندما يشير تابع الصنف إلى | يمكن استدعاء توابع الأصناف مباشرة، ولعلّك تجد ذلك غريبًا، لكنّ التابع الخاص بالوحدة يطلق عليه تابع الصنف (class method) بدلًا من تابع الوحدة (module method)، انظر أيضًا صفحة التوثيق الخاصّة بالوحدات في لغة روبي إذ بإمكانك تحويل تابع نسخة (instance method) معرّف في وحدة إلى تابع صنف. | ||
تُستدعى توابع | |||
<syntaxhighlight lang="ruby"> | عندما يشير تابع الصنف إلى ثابت، ستُطبق حينها ذات القواعد عند الإشارة إليه خارج التابع، إذ أنّ النطاق نفسه في الحالتين. | ||
تُستدعى توابع النسخة المعرّفة في الوحدات عند تضمينها حصرًا. ويكون لها وصول إلى الثوابت المعرّفة عند تضمينها في شجرة الآباء: <syntaxhighlight lang="ruby"> | |||
module A | module A | ||
Z = 1 | Z = 1 | ||
سطر 91: | سطر 86: | ||
p z #=> 1 | p z #=> 1 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== المرئية === | ====المرئية==== | ||
توفّر لغة روبي ثلاثة مستويات من المرئية. المستوى الافتراضي هو المرئية العامّة Public. فالتابع العام يمكن استدعاؤه من أيّ كائن آخر. | توفّر لغة روبي ثلاثة مستويات من المرئية (Visibility). المستوى الافتراضي هو المرئية العامّة (Public). فالتابع العام يمكن استدعاؤه من أيّ كائن آخر. | ||
المستوى الثاني للمرئية هو المرئية المحمية | |||
كثيرًا ما تستخدم المرئيّة المحميّة لتعريف معامل == وتوابع المقارنة الأخرى حيث لا يرغب المؤلّف بإتاحة حالة الكائنات لكلّ من يرغب باستدعائها، بل يحصر ذلك في الأصناف الفرعية. | المستوى الثاني للمرئية هو المرئية المحمية (protected)، ففي حالة استدعاء التابع المحمي، يجب أن يكون المرسل صنفًا فرعيًا من المستقبل أو أن يكون المستقبل صنفًا فرعيًّا من المرسل؛ عدا ذلك، سيظهر استثناء من النوع <code>[[Ruby/NoMethodError|NoMethodError]]</code>. | ||
إليك مثالًا: | |||
<syntaxhighlight lang="ruby"> | كثيرًا ما تستخدم المرئيّة المحميّة لتعريف معامل <code>==</code> وتوابع المقارنة الأخرى حيث لا يرغب المؤلّف بإتاحة حالة الكائنات لكلّ من يرغب باستدعائها، بل يحصر ذلك في الأصناف الفرعية. إليك مثالًا عن ذلك:<syntaxhighlight lang="ruby"> | ||
class A | class A | ||
def n(other) | def n(other) | ||
سطر 115: | سطر 110: | ||
c.n b #=> 1 -- C صنف فرعيّ من B | c.n b #=> 1 -- C صنف فرعيّ من B | ||
b.n b #=> 1 -- mاستدعي في الصنف المعرَّف | b.n b #=> 1 -- mاستدعي في الصنف المعرَّف | ||
a.n b # | a.n b # NoMethodError A is not a subclass of B يظهر الخطأ | ||
</syntaxhighlight> | </syntaxhighlight>المستوى الثالث للمرئية هو المرئية الخاصّة (private). فالتوابع الخاصة لا يمكن استدعاؤها عن طريق مستقبل ولا حتى <code>self</code>. وإذا استدعيت بهذه الطريقة فسيرمى الاستثناء <code>[[Ruby/NoMethodError|NoMethodError]]</code>. | ||
المستوى الثالث للمرئية هو المرئية الخاصّة. فالتوابع الخاصة لا يمكن استدعاؤها عن طريق مستقبل ولا حتى self. وإذا استدعيت بهذه الطريقة | |||
==== الأسماء البديلة وإلغاء التعريف ==== | |||
يمكنك | يمكنك إنشاء أسماء بديلة للتوابع أو إلغاء تعريفها، إلا أنّ هذه العمليات ليست خاصّة بالوحدات أو الأصناف. راجع توثيق [[Ruby/miscellaneous|الصيغ المنوَّعة]] في لغة روبي لمزيد من التفاصيل. | ||
= الأصناف = | ==الأصناف== | ||
الأصناف هي وحدات إلا أنّها لا يمكن استخدامها للخلط الضمنيّ mix-in ضمن وحدات أو أصناف أخرى. ويمكن استخدام الأصناف كالوحدات في حجز نطاق الأسماء، كما يمكن للصنف أن يرث التوابع والثوابت من الأصناف الأكبر. | الأصناف هي وحدات إلا أنّها لا يمكن استخدامها للخلط الضمنيّ (mix-in) ضمن وحدات أو أصناف أخرى. ويمكن استخدام الأصناف كالوحدات في حجز نطاق الأسماء، كما يمكن للصنف أن يرث التوابع والثوابت من الأصناف الأكبر. | ||
== تعريف الصنف == | ===تعريف الصنف=== | ||
استخدم الكلمة class لتعريف الصنف: | استخدم الكلمة <code>class</code> لتعريف الصنف:<syntaxhighlight lang="ruby"> | ||
<syntaxhighlight lang="ruby"> | |||
class MyClass | class MyClass | ||
# ... | # ... | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>إذا لم تكتب الصنف الأب فسيرث هذا الصنف من <code>[[Ruby/Object|Object]]</code>. ويمكنك أن تحدد الصنف الأب باستخدام <code>></code> متبوعًا باسم الصنف الأب:<syntaxhighlight lang="ruby"> | ||
إذا لم تكتب الصنف الأب فسيرث هذا الصنف من Object. ويمكنك أن تحدد الصنف الأب باستخدام > | |||
<syntaxhighlight lang="ruby"> | |||
class MySubclass < MyClass | class MySubclass < MyClass | ||
# ... | # ... | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>يوجد في لغة روبي صنفًا خاصًّا اسمه <code>[[Ruby/BasicObject|BasicObject]]</code> صُمّم لأن يكون صنفًا فارغًا ويتضمن حدًّا أدنى من التوابع المعرّفة مسبقًا، فبإمكانك استخدام هذا الصنف لتنشئ هيكلية وراثة مستقلة. انظر صفحة التوثيق الخاصّة بالصنف <code>[[Ruby/BasicObject|BasicObject]]</code> لمزيد من التفاصيل. | ||
يوجد في لغة روبي صنفًا خاصًّا اسمه BasicObject صُمّم لأن يكون صنفًا فارغًا ويتضمن حدًّا أدنى من التوابع المعرّفة مسبقًا، فبإمكانك استخدام هذا الصنف لتنشئ هيكلية وراثة مستقلة. انظر صفحة التوثيق الخاصّة | ===الوراثة=== | ||
== الوراثة == | كل تابع معرّف في صنف أب معيّن يمكن استدعاؤه من الأصناف الفرعية:<syntaxhighlight lang="ruby"> | ||
<syntaxhighlight lang="ruby"> | |||
class A | class A | ||
Z = 1 | Z = 1 | ||
سطر 148: | سطر 138: | ||
end | end | ||
p B.new.z #=> 1 | p B.new.z #=> 1 | ||
</syntaxhighlight> | </syntaxhighlight>والأمر نفسه يطبّق على الثوابت:<syntaxhighlight lang="ruby"> | ||
والأمر نفسه يطبّق على الثوابت: | |||
<syntaxhighlight lang="ruby"> | |||
class A | class A | ||
Z = 1 | Z = 1 | ||
سطر 160: | سطر 148: | ||
end | end | ||
p B.new.z #=> 1 | p B.new.z #=> 1 | ||
</syntaxhighlight> | </syntaxhighlight>كما بإمكانك التعديل على وظيفة موجودة في الصنف الأب عن طريق إعادة تعريف التابع في الصنف الفرعي:<syntaxhighlight lang="ruby"> | ||
كما بإمكانك التعديل على وظيفة موجودة في الصنف الأب عن طريق إعادة تعريف التابع في الصنف الفرعي: | |||
<syntaxhighlight lang="ruby"> | |||
class A | class A | ||
def m | def m | ||
سطر 174: | سطر 160: | ||
end | end | ||
p B.new.m #=> 2 | p B.new.m #=> 2 | ||
</syntaxhighlight> | </syntaxhighlight>إذا أردت طلب وظيفة يقوم بها التابع المعرّف في الصنف الأب، فاستخدم كلمة <s>super</s>:<syntaxhighlight lang="ruby"> | ||
إذا أردت طلب وظيفة يقوم بها التابع المعرّف في الصنف | |||
<syntaxhighlight lang="ruby"> | |||
class A | class A | ||
def m | def m | ||
سطر 188: | سطر 172: | ||
end | end | ||
p B.new.m #=> 3 | p B.new.m #=> 3 | ||
</syntaxhighlight> | </syntaxhighlight>إذا كتبت <code>super</code> بدون أيّ معاملات فستأخذ المعاملات التي مُرّرت إلى التابع في الصنف الفرعي. أمّا لم ترد إرسال أيّ وسائط، فاكتب <code>()super</code>. وإذا أردت إرسال وسائط محدّدة، فاكتبها يدويًّا مثل <code>(super(2</code>. وليس هناك قيد على عدد المرات التي يمكنك استدعاء <code>super</code> بها، بل استخدمها كلما أردت. | ||
إذا كتبت super بدون أيّ معاملات فستأخذ المعاملات التي مُرّرت إلى التابع في الصنف الفرعي. أمّا لم ترد إرسال أيّ | ===الصنف المنفرد=== | ||
== الصنف المنفرد | الصنف المنفرد (Singleton، ويعرف أيضًا بالصنف المجرّد [metaclass] أو الصنف الخاص [eigenclass]) هو الصنف الذي يحوي التوابع الخاصّة بكائن معيّن دون غيره. ويمكنك الوصول إلى الصنف المنفرد الخاصّ بكائن ما عن طريق كتابة الصيغة <code>class>>object</code> كما في المثال:<syntaxhighlight lang="ruby"> | ||
الصنف المنفرد (ويعرف أيضًا بالصنف المجرّد metaclass أو الصنف الخاص) هو الصنف الذي يحوي التوابع الخاصّة بكائن معيّن دون غيره. ويمكنك الوصول إلى الصنف المنفرد الخاصّ بكائن ما عن طريق كتابة الصيغة class>>object كما في المثال: | |||
<syntaxhighlight lang="ruby"> | |||
class C | class C | ||
end | end | ||
class << C | class << C | ||
# | # هنا هي الصنف المنفرد self | ||
end | end | ||
كثيرًا ما ستجد أن الصيغة التالية مستخدمة للوصول إلى الصنف المنفرد: | |||
</syntaxhighlight>كثيرًا ما ستجد أن الصيغة التالية مستخدمة للوصول إلى الصنف المنفرد:<syntaxhighlight lang="ruby"> | |||
class C | class C | ||
class << self | |||
# ... | |||
end | |||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>وهذه الصيغة تسمح بتعريف توابع وواصفات للصنف (أو الوحدة) بدون الحاجة إلى كتابة <code>def self.my_method</code>. | ||
وهذه الصيغة تسمح بتعريف توابع وواصفات للصنف (أو الوحدة) بدون الحاجة إلى كتابة def self.my_method | |||
وبما أنّك تستطيع أن تفتح أيّ صنف منفرد لأيّ كائن على | وبما أنّك تستطيع أن تفتح أيّ صنف منفرد لأيّ كائن على الإطلاق، فهذا يعني أنّ الكتلة البرمجية التالية:<syntaxhighlight lang="ruby"> | ||
<syntaxhighlight lang="ruby"> | |||
o = Object.new | o = Object.new | ||
def o.my_method | def o.my_method | ||
1 + 1 | 1 + 1 | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>تكافئ هذه الكتلة:<syntaxhighlight lang="ruby"> | ||
تكافئ هذه الكتلة: | |||
<syntaxhighlight lang="ruby"> | |||
o = Object.new | o = Object.new | ||
class << o | class << o | ||
سطر 221: | سطر 201: | ||
end | end | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight>وسيكون لكلا الكائنين تابعًا اسمه <code>my_method</code> يعيد القيمة 2. | ||
وسيكون لكلا الكائنين تابعًا اسمه my_method يعيد القيمة 2. | ==المصادر== | ||
*[https://ruby-doc.org/core-2.5.1/doc/syntax/refinements_rdoc.html صفحة Modules and Classes في توثيق روبي الرسمي] | |||
== المصادر == | [[تصنيف:Ruby]] | ||
* [https://ruby-doc.org/core-2.5.1/doc/syntax/refinements_rdoc.html صفحة Modules and Classes في توثيق روبي الرسمي] | [[تصنيف:Ruby Syntax]] |
المراجعة الحالية بتاريخ 08:11، 19 نوفمبر 2018
الوحدات
تخدم الوحدات (Modules) غايتين اثنتين في لغة روبي وهما: ميّزة نطاقات الأسماء (namespace)، والخلط الضمني (mix-in) التي سنوضّحها لاحقًا.
يستخدم نطاق الأسماء لتنظيم الشيفرة البرمجية ضمن مجموعات مستقلّة تمنع تداخل التوابع والمتغيّرات ذات الأسماء المتشابهة فيما بينها. فعلى سبيل المثال، نطاق الأسماء IRB يوفّر عمليات irb والتي تمنع التصادم مع الاسم الشائع "Context".
وظيفة الخلط الضمني (Mix-in) تسمح بمشاركة توابع مشتركة عبر عدد من الأصناف أو الوحدات، إذ يأتي مع لغة روبي على سبيل المثال الوحدة Enumerable
التي توفّر توابع حساب (enumeration) مبنية على التابع each
. كما تسمح الوحدة Comparable
بموازنة الكائنات بناء على تابع الموازنة <=>
.
لاحظ وجود شبه كبير بين الوحدات والأصناف، بالإضافة إلى إمكانية الخلط الضمني داخل الوحدة، فوصف الوحدات أدناه يمكن تطبيقه كذلك على الأصناف.
تعريف الوحدة
تُنشأ الوحدة باستخدام الكلمة المحجوزة module
:
module MyModule
# ...
end
يمكن إعادة فتح الوحدة عددًا غير محدود من المرات لإضافة أو تعديل أو حذف وظائف منها.
module MyModule
def my_method
end
end
module MyModule
alias my_alias my_method
end
module MyModule
remove_method :my_method
end
تُعدّ إعادة فتح الأصناف ميّزة فعّالة جدًا في لغة روبي، لكنّ الاستخدام الأمثل لها يكمن في إعادة فتح أصنافك الخاصّة، لأنّ فتح أصناف أخرى لا تمتلكها أنت قد يؤدي إلى تضاربات أو صعوبة في تتبع الأخطاء.
التشعب
يمكن تعريف الوحدات داخل بعضها بشكل متشعب (nested):
module Outer
module Inner
end
end
كثير من الحزم في لغة روبي تعرّف وحدةً أو صنفًا خارجيًّا ليؤمّن نطاق أسماء خاصّ بالعمليات الخاصة بهذه الحزمة.
كما بإمكانك تعريف الوحدات الضمنية باستخدام ::
على أن يكون الصنف أو الوحدة الكبرى معرّفة مسبقًا:
module Outer::Inner::GrandChild
end
لاحظ أنّ هذا المثال سيسبب الخطأ NameError
إذا لم تكن الوحدة Outer
والوحدة الضمنية Outer::Inner
معرفتان.
هذا الأسلوب يفيد المؤلّف في تخفيض عدد المسافات البادئة للشيفرة البرمجية من ثلاثة مستويات إلى مستوى واحد. إلا أنّ نطاق البحث عن المتغيّرات يختلف عند إنشاء نطاق أسماء باستخدام الصيغة الأساسية بدلًا من الصيغة المختصرة.
النطاق
الكائن الذاتي self
يشير self
إلى الكائن الذي يعرّف النطاق الحاليّ، ويتغيّر هذا الكائن عند دخول تابع مختلف أو عند تعريف وحدة جديدة.
الثوابت
الثوابت التي يمكن الوصول إليها تختلف تبعًا لصيغة التعريف الضمنيّ للوحدات. ففي المثال التالي، يعدّ الثابت A::Z
قابلًا للوصول من B
على فرض أنّ A
هو جزء من عملية التضمين:
module A
Z = 1
module B
p Module.nesting #=> [A::B, A]
p Z #=> 1
end
end
إلا أنّك إذا استخدمت الرمز ::
لتعريف الوحدة الضمنية A::B
بدون كتابتها داخل الوحدة A
، فسيظهر خطأ من النوع NameError
بسبب كون التضمين لا يحوي الوحدة A
.
module A
Z = 1
end
module A::B
p Module.nesting #=> [A::B]
p Z #=> يسبب NameError
end
وإذا عُرّف الثابت في نطاق خارج جميع الوحدات، فبإمكانك حينها كتابته مسبوقًا بالنقطتين ::
للإشارة إليه:
Z = 0
module A
Z = 1
module B
p ::Z #=> 0
end
end
التوابع
راجع صفحة التوثيق الخاصة بصيغة التوابع لتتعرف على صيغة تعريفها.
يمكن استدعاء توابع الأصناف مباشرة، ولعلّك تجد ذلك غريبًا، لكنّ التابع الخاص بالوحدة يطلق عليه تابع الصنف (class method) بدلًا من تابع الوحدة (module method)، انظر أيضًا صفحة التوثيق الخاصّة بالوحدات في لغة روبي إذ بإمكانك تحويل تابع نسخة (instance method) معرّف في وحدة إلى تابع صنف.
عندما يشير تابع الصنف إلى ثابت، ستُطبق حينها ذات القواعد عند الإشارة إليه خارج التابع، إذ أنّ النطاق نفسه في الحالتين.
تُستدعى توابع النسخة المعرّفة في الوحدات عند تضمينها حصرًا. ويكون لها وصول إلى الثوابت المعرّفة عند تضمينها في شجرة الآباء:
module A
Z = 1
def z
Z
end
end
include A
p self.class.ancestors #=> [Object, A, Kernel, BasicObject]
p z #=> 1
المرئية
توفّر لغة روبي ثلاثة مستويات من المرئية (Visibility). المستوى الافتراضي هو المرئية العامّة (Public). فالتابع العام يمكن استدعاؤه من أيّ كائن آخر.
المستوى الثاني للمرئية هو المرئية المحمية (protected)، ففي حالة استدعاء التابع المحمي، يجب أن يكون المرسل صنفًا فرعيًا من المستقبل أو أن يكون المستقبل صنفًا فرعيًّا من المرسل؛ عدا ذلك، سيظهر استثناء من النوع NoMethodError
.
كثيرًا ما تستخدم المرئيّة المحميّة لتعريف معامل ==
وتوابع المقارنة الأخرى حيث لا يرغب المؤلّف بإتاحة حالة الكائنات لكلّ من يرغب باستدعائها، بل يحصر ذلك في الأصناف الفرعية. إليك مثالًا عن ذلك:
class A
def n(other)
other.m
end
end
class B < A
def m
1
end
protected :m
end
class C < B
end
a = A.new
b = B.new
c = C.new
c.n b #=> 1 -- C صنف فرعيّ من B
b.n b #=> 1 -- mاستدعي في الصنف المعرَّف
a.n b # NoMethodError A is not a subclass of B يظهر الخطأ
المستوى الثالث للمرئية هو المرئية الخاصّة (private). فالتوابع الخاصة لا يمكن استدعاؤها عن طريق مستقبل ولا حتى self
. وإذا استدعيت بهذه الطريقة فسيرمى الاستثناء NoMethodError
.
الأسماء البديلة وإلغاء التعريف
يمكنك إنشاء أسماء بديلة للتوابع أو إلغاء تعريفها، إلا أنّ هذه العمليات ليست خاصّة بالوحدات أو الأصناف. راجع توثيق الصيغ المنوَّعة في لغة روبي لمزيد من التفاصيل.
الأصناف
الأصناف هي وحدات إلا أنّها لا يمكن استخدامها للخلط الضمنيّ (mix-in) ضمن وحدات أو أصناف أخرى. ويمكن استخدام الأصناف كالوحدات في حجز نطاق الأسماء، كما يمكن للصنف أن يرث التوابع والثوابت من الأصناف الأكبر.
تعريف الصنف
استخدم الكلمة class
لتعريف الصنف:
class MyClass
# ...
end
إذا لم تكتب الصنف الأب فسيرث هذا الصنف من Object
. ويمكنك أن تحدد الصنف الأب باستخدام >
متبوعًا باسم الصنف الأب:
class MySubclass < MyClass
# ...
end
يوجد في لغة روبي صنفًا خاصًّا اسمه BasicObject
صُمّم لأن يكون صنفًا فارغًا ويتضمن حدًّا أدنى من التوابع المعرّفة مسبقًا، فبإمكانك استخدام هذا الصنف لتنشئ هيكلية وراثة مستقلة. انظر صفحة التوثيق الخاصّة بالصنف BasicObject
لمزيد من التفاصيل.
الوراثة
كل تابع معرّف في صنف أب معيّن يمكن استدعاؤه من الأصناف الفرعية:
class A
Z = 1
def z
Z
end
end
class B < A
end
p B.new.z #=> 1
والأمر نفسه يطبّق على الثوابت:
class A
Z = 1
end
class B < A
def z
Z
end
end
p B.new.z #=> 1
كما بإمكانك التعديل على وظيفة موجودة في الصنف الأب عن طريق إعادة تعريف التابع في الصنف الفرعي:
class A
def m
1
end
end
class B < A
def m
2
end
end
p B.new.m #=> 2
إذا أردت طلب وظيفة يقوم بها التابع المعرّف في الصنف الأب، فاستخدم كلمة super:
class A
def m
1
end
end
class B < A
def m
2 + super
end
end
p B.new.m #=> 3
إذا كتبت super
بدون أيّ معاملات فستأخذ المعاملات التي مُرّرت إلى التابع في الصنف الفرعي. أمّا لم ترد إرسال أيّ وسائط، فاكتب ()super
. وإذا أردت إرسال وسائط محدّدة، فاكتبها يدويًّا مثل (super(2
. وليس هناك قيد على عدد المرات التي يمكنك استدعاء super
بها، بل استخدمها كلما أردت.
الصنف المنفرد
الصنف المنفرد (Singleton، ويعرف أيضًا بالصنف المجرّد [metaclass] أو الصنف الخاص [eigenclass]) هو الصنف الذي يحوي التوابع الخاصّة بكائن معيّن دون غيره. ويمكنك الوصول إلى الصنف المنفرد الخاصّ بكائن ما عن طريق كتابة الصيغة class>>object
كما في المثال:
class C
end
class << C
# هنا هي الصنف المنفرد self
end
كثيرًا ما ستجد أن الصيغة التالية مستخدمة للوصول إلى الصنف المنفرد:
class C
class << self
# ...
end
end
وهذه الصيغة تسمح بتعريف توابع وواصفات للصنف (أو الوحدة) بدون الحاجة إلى كتابة def self.my_method
.
وبما أنّك تستطيع أن تفتح أيّ صنف منفرد لأيّ كائن على الإطلاق، فهذا يعني أنّ الكتلة البرمجية التالية:
o = Object.new
def o.my_method
1 + 1
end
تكافئ هذه الكتلة:
o = Object.new
class << o
def my_method
1 + 1
end
end
وسيكون لكلا الكائنين تابعًا اسمه my_method
يعيد القيمة 2.