الوحدات في 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"
Bellebrook Basketball League دوري يضم عدة فرق، ولكل فريق قائمة من اللاعبين. يوشك موسم جديد على البدء، ويحتاجون إلى إنشاء نظام تذاكر جديد لبيع تذاكر المباريات. في الموسم الماضي، باعوا التذاكر عند مدخل الملعب، لكن الشعبية ارتفعت بشكل كبير، فقرروا بيع التذاكر عبر الإنترنت هذا الموسم للتعامل مع الطلب المتزايد.
تواصل معك الدوري وطلب منك إنشاء نظام للتعامل مع بيع التذاكر.
أولًا، تحتاج إلى إنشاء نظام تذاكر للتعامل مع بيع التذاكر. يحتاج نظام التذاكر إلى تحديد عدد التذاكر المتاحة لمباراة.
يجب إنشاء نسخة من صنف يُسمى TicketSystem لكل مباراة.
يجب أن تحمل الحالة المُهيّأة المعلومات التالية:
أنشئ حالة مُهيّأة من وسائط تشير إلى عدد التذاكر المتاحة والملعب الذي تُلعب فيه المباراة.
يجب أن تتكون الحالة المُهيّأة من متغيرات المثيل @tickets_available و @stadium.
يجب أن تحتوي هاتان على الوسيطين الأول والثاني المُعطيين، على التوالي.
TicketSystem.new(100, "Bellebrook")
# => #<TicketSystem:0x10f0b8 @tickets_available=100, @stadium="Bellebrook">
أولًا، تحتاج إلى إنشاء طريقة تُرجع عدد التذاكر المتاحة لمباراة معينة.
عرّف وحدة تُسمى TicketingReservation فوق الصنف المُعرَّف مسبقًا.
يجب تضمين هذه الوحدة في صنف TicketSystem.
داخل الوحدة، عرّف طريقة تُسمى tickets_available.
يجب أن تُرجع هذه الطريقة عدد التذاكر المتاحة.
ticket_system = TicketSystem.new(100)
ticket_system.tickets_available
#=> 100
يجب عليك إنشاء طريقة تتحقق مما إذا كانت التذاكر متاحة لمباراة معينة. تحتاج المباراة إلى الاحتفاظ بـ 100 تذكرة في الاحتياط. وذلك لضمان وجود تذاكر متاحة دائمًا للأشخاص الذين يشترون التذاكر عند مدخل الملعب.
داخل الوحدة TicketingReservation، عرّف طريقة تُسمى order_ticket?.
يجب أن تُرجع الطريقة true إذا كانت 100 تذكرة على الأقل متاحة و false خلاف ذلك.
وإذا كانت 100 تذكرة على الأقل متاحة، يجب أن تُقلل الطريقة أيضًا عدد التذاكر المتاحة بمقدار 1.
ticket_system = TicketSystem.new(100)
ticket_system.order_ticket?
#=> true
يجب أن يحتوي نظام التذاكر على رسائل سهلة الفهم للمستخدمين. وينبغي أن تبدو الرسائل شخصية، لذا يجب أن تتضمن اسم المستخدم.
إذا نجحت عملية شراء التذكرة، يجب أن يتلقى المستخدم رسالة تخبره بأن الشراء قد نجح، ورقم تذكرته، والملعب الذي تُلعب فيه المباراة. يجب أن يكون رقم التذكرة هو عدد التذاكر المتاحة قبل الطلب.
إذا نجح الشراء، يجب أن تبدو الرسالة هكذا: {name}, your purchase was successful, your ticket number is #{ticket_number}, and the game is played at the {stadium_name} stadium..
وإذا لم ينجح الشراء، يجب أن تبدو الرسالة هكذا: {name}, your purchase was unsuccessful, there are not enough tickets available..
داخل الوحدة TicketingReservation, عرّف طريقة تُسمى order_message تتلقى وسيطًا name يحتوي على اسم المشتري.
يجب أن تُرجع الطريقة سلسلة نصية تحتوي على الرسالة.
ticket_system = TicketSystem.new(100, "Bellebrook")
ticket_system.order_message("John")
#=> "John, your purchase was successful, your ticket number is #100, and the game is played at the Bellebrook stadium."
سجّل في Exercism لتتعلّم وتتقن Crystal عبر 26 مفهومًا142 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.