الوحدات في Crystal تخدم غرضين:
الغرض الأول هو إنشاء فضاء أسماء لتجنّب تعارض الأسماء. لكنه يجمع الكود أيضًا، مما يسهّل فهم الغرض من الكود.
الغرض الثاني هو تعريف مزائج لمشاركة الكود مع الأنواع.
الوحدات تشبه الأصناف، لكن الفرق الأساسي أنها لا يمكن إنشاء كائنات منها، وبالتالي لا تحتوي على متغيرات نسخة.
لتعريف وحدة، تستخدم الكلمة المفتاحية module متبوعة باسم الوحدة.
module Foo
end
فضاء الأسماء هو أسلوب لتجميع الكود.
هذا يتجنّب تعارض الأسماء ويسهّل فهم الغرض من الكود.
عند الرغبة في الوصول إلى ثابت أو صنف موضوع داخل فضاء الأسماء، تستخدم العامل ::.
module Foo
class Bar
end
end
Foo::Bar.new
يمكن أن يكون هذا مفيدًا عندما، على سبيل المثال، تحتاج أصناف متعددة إلى نفس الوظائف "الأساسية"، أو عندما يحتاج الكود إلى المشاركة بين أصناف غير مرتبطة. أو عند الرغبة في مشاركة الكود بين أصناف لا تربطها علاقة.
هناك أسلوبان مختلفان لاستخدام وحدة كمزيج: الأول هو استخدام الكلمة المفتاحية include، والثاني هو استخدام الكلمة المفتاحية extend.
سيتيح كلا الأسلوبين الثوابت للنوع الذي يضم أو يوسّع الوحدة.
ستجعل include جميع الطرق في الوحدة متاحة كطرق نسخة على النوع الذي يضم الوحدة.
ينبغي أن تكون الكلمة المفتاحية include في أعلى النوع، متبوعة باسم الوحدة.
module Foo
def foo
"foo"
end
end
class Bar
include Foo
end
Bar.new.foo # => "foo"
تعمل extend بشكل مشابه لـ include، لكن بدلًا من جعل الطرق متاحة كطرق نسخة، فإنها تجعلها متاحة كطرق صنف.
ينبغي أن تُكتب الكلمة المفتاحية extend في أعلى النوع، متبوعة باسم الوحدة.
module Foo
def foo
"foo"
end
end
class Bar
extend Foo
end
Bar.foo # => "foo"
ثمة نمط شائع في Crystal يستخدم نمط extend self داخل وحدة.
سيجعل هذا جميع الطرق في الوحدة متاحة كطرق صنف على الوحدة نفسها.
هذا يعني أنك لست مضطرًا لربط كل طريقة بالوحدة باستخدام صيغة def self.method_name.
module Foo
extend self
def foo
"foo"
end
end
Foo.foo # => "foo"