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

من موسوعة حسوب
لا ملخص تعديل
طلا ملخص تعديل
 
(1 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة)
سطر 1: سطر 1:
= الوحدات =
<noinclude>{{DISPLAYTITLE:الوحدات والأصناف في روبي}}</noinclude>
تخدم الوحدات غايتين اثنتين في لغة روبي وهما نطاقات الأسماء، وميّزة الخلط الضمني mix-in التي سنوضّحها لاحقًا.
==الوحدات==
يستخدم نطاق الأسماء namespace لتنظيم الشيفرة البرمجية ضمن مجموعات مستقلّة تمنع تداخل التوابع والمتغيّرات ذات الأسماء المتشابهة فيما بينها. فعلى سبيل المثال، نطاق الأسماء IRB يوفّر عمليات irb والتي تمنع التصادم مع الاسم الشائع Context.
تخدم الوحدات (Modules) غايتين اثنتين في لغة روبي وهما: ميّزة نطاقات الأسماء (namespace)، والخلط الضمني (mix-in) التي سنوضّحها لاحقًا.
وظيفة الخلط الضمني Mix-in تسمح بمشاركة توابع مشتركة عبر عدد من الأصناف أو الوحدات. إذ يأتي مع لغة روبي على سبيل المثال وحدة Enumerable التي توفّر توابع حساب enumeration مبنية على تابع each. كما تسمح وحدة Comparable بمقارنة الكائنات بناء على تابع المقارنة <=>.
 
يستخدم نطاق الأسماء لتنظيم الشيفرة البرمجية ضمن مجموعات مستقلّة تمنع تداخل التوابع والمتغيّرات ذات الأسماء المتشابهة فيما بينها. فعلى سبيل المثال، نطاق الأسماء 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>تُعدّ إعادة فتح الأصناف ميّزة فعّالة جدًا في لغة روبي، لكنّ الاستخدام الأمثل لها يكمن في إعادة فتح أصنافك الخاصّة، لأنّ فتح أصناف أخرى لا تمتلكها أنت قد يؤدي إلى تضاربات أو صعوبة في تتبع الأخطاء.
تُعدّ إعادة فتح الأصناف ميّزة فعّالة جدًا في لغة روبي، لكنّ الاستخدام الأمثل لها يكمن في إعادة فتح أصنافك الخاصّة، لأنّ فتح أصناف أخرى لا تمتلكها أنت قد يؤدي إلى تضاربات أو صعوبة في تتبع الأخطاء.
===التشعب===
== التضمين Nesting ==
يمكن تعريف الوحدات داخل بعضها بشكل متشعب (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> معرفتان.
لاحظ أنّ هذا المثال سيسبب خطأ تسمية NameError إذا لم تكن الوحدة Outer والوحدة الضمنية Outer::Inner معرفتان.
 
هذا الأسلوب يفيد المؤلّف في تخفيض عدد المسافات البادئة للشيفرة البرمجية من ثلاثة مستويات إلى مستوى واحد. إلا أنّ نطاق البحث عن المتغيّرات يختلف عند إنشاء نطاق أسماء باستخدام الصيغة الأساسية بدلًا من الصيغة المختصرة.
هذا الأسلوب يفيد المؤلّف في تخفيض عدد المسافات البادئة للشيفرة البرمجية من ثلاثة مستويات إلى مستوى واحد. إلا أنّ نطاق البحث عن المتغيّرات يختلف عند إنشاء نطاق أسماء باستخدام الصيغة الأساسية بدلًا من الصيغة المختصرة.
== النطاق ==
===النطاق===
=== الكائن الذاتي self ===
====الكائن الذاتي <code>self</code>====
يشير self إلى الكائن الذي يعرّف النطاق الحاليّ، ويتغيّر هذا الكائن عند دخول تابع مختلف أو عند تعريف وحدة جديدة.
يشير <code>self</code> إلى الكائن الذي يعرّف النطاق الحاليّ، ويتغيّر هذا الكائن عند دخول تابع مختلف أو عند تعريف وحدة جديدة.
=== الثوابت ===
====الثوابت====
الثوابت التي يمكن الوصول إليها تختلف تبعًا لصيغة التعريف الضمنيّ للوحدات. ففي المثال التالي يعدّ الثابت A::Z قابلًا للوصول من B على اعتبار أنّ A هو جزء من عملية التضمين:
الثوابت التي يمكن الوصول إليها تختلف تبعًا لصيغة التعريف الضمنيّ للوحدات. ففي المثال التالي، يعدّ الثابت <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 بدون كتابتها داخل الوحدة فسيظهر خطأ من نوع NameError بسبب كون التضمين لا يحوي الوحدة A.
<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|التوابع]] لتتعرف على صيغة تعريفها.
يمكن استدعاء توابع الأصناف مباشرة، ولعلّك تجد ذلك غريبًا، لكنّ التابع الخاص بالوحدة يطلق عليه تابع الصنف بدلًا من تابع الوحدة، انظر أيضًا صفحة التوثيق الخاصّة بالوحدات في لغة روبي إذ بإمكانك تحويل تابع مثال instance method معرّف  في وحدة إلى تابع صنف.
 
عندما يشير تابع الصنف إلى ثابت فستُطبق حينها ذات القواعد عند الإشارة إليه خارج التابع، إذ أنّ النطاق نفسه في الحالتين.
يمكن استدعاء توابع الأصناف مباشرة، ولعلّك تجد ذلك غريبًا، لكنّ التابع الخاص بالوحدة يطلق عليه تابع الصنف (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، ففي حالة استدعاء التابع المحمي يجب أن يكون المرسل صنفًا فرعيًا من المستقبل أو أن يكون المستقبل صنفًا فرعيًّا من المرسل، عدا ذلك سيظهر استثناء من نوع NoMethodError.
 
كثيرًا ما تستخدم المرئيّة المحميّة لتعريف معامل == وتوابع المقارنة الأخرى حيث لا يرغب المؤلّف بإتاحة حالة الكائنات لكلّ من يرغب باستدعائها، بل يحصر ذلك في الأصناف الفرعية.
المستوى الثاني للمرئية هو المرئية المحمية (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 # يظهر خطأ NoMethodError A is not a subclass of B
a.n b # NoMethodError A is not a subclass of B يظهر الخطأ
</syntaxhighlight>
</syntaxhighlight>المستوى الثالث للمرئية هو المرئية الخاصّة (private). فالتوابع الخاصة لا يمكن استدعاؤها عن طريق مستقبل ولا حتى <code>self</code>. وإذا استدعيت بهذه الطريقة فسيرمى الاستثناء <code>[[Ruby/NoMethodError|NoMethodError]]</code>.
المستوى الثالث للمرئية هو المرئية الخاصّة. فالتوابع الخاصة لا يمكن استدعاؤها عن طريق مستقبل ولا حتى self. وإذا استدعيت بهذه الطريقة فسيظهر استثناء NoMethodError
 
المماثلة alias وإلغاء التعريف undef
==== الأسماء البديلة وإلغاء التعريف ====
يمكنك مماثلة أو إلغاء تعريف التوابع، إلا أنّ هذه العمليات ليست خاصّة بالوحدات او الأصناف. راجع توثيق الصيغ المنوعة في لغة روبي لمزيد من التفاصيل
يمكنك إنشاء أسماء بديلة للتوابع أو إلغاء تعريفها، إلا أنّ هذه العمليات ليست خاصّة بالوحدات أو الأصناف. راجع توثيق [[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 صُمّم لأن يكون صنفًا فارغًا ويتضمن حدًّا أدنى من التوابع المعرّفة مسبقًا، فبإمكانك استخدام هذا الصنف لتنشئ هيكلية وراثة مستقلة. انظر صفحة التوثيق الخاصّة بـ 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">
إذا أردت طلب وظيفة يقوم بها التابع المعرّف في الصنف الأب فاستخدم كلمة super:
<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 بدون أيّ معاملات فستأخذ المعاملات التي مُرّرت إلى التابع في الصنف الفرعي. أمّا لم ترد إرسال أيّ معاملات فاكتب super(). وإذا أردت إرسال معاملات محدّدة فاكتبها يدويًّا مثل super(2). وليس هناك قيد على عدد المرات التي يمكنك استدعاء super بها، بل استخدمها كلما أردت.
===الصنف المنفرد===
== الصنف المنفرد Singleton ==
الصنف المنفرد (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 هنا هي الصنف المنفرد
 # هنا هي الصنف المنفرد self
end
end
كثيرًا ما ستجد أن الصيغة التالية مستخدمة للوصول إلى الصنف المنفرد:
 
</syntaxhighlight>كثيرًا ما ستجد أن الصيغة التالية مستخدمة للوصول إلى الصنف المنفرد:<syntaxhighlight lang="ruby">
class C
class C
 class << self
  class << self
   # ...
    # ...
 end
  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.

المصادر