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

من موسوعة حسوب
ط ! تعديل مثال
ط تصحيح التنسيق
سطر 15: سطر 15:
بمجرّد أن يتمّ إسناد قيمة إلى المتغيّر المحلّيّ فكلّ استخدامات اسم هذا المتغيّر ضمن النطاق نفسه سيتمّ اعتبارها متغيّرات محليّة. وإليك هذا المثال:<syntaxhighlight lang="ruby">
بمجرّد أن يتمّ إسناد قيمة إلى المتغيّر المحلّيّ فكلّ استخدامات اسم هذا المتغيّر ضمن النطاق نفسه سيتمّ اعتبارها متغيّرات محليّة. وإليك هذا المثال:<syntaxhighlight lang="ruby">
1.times do
1.times do
 a = 1
 a = 1
 puts "local variables in the block: #{local_variables.join ", "}"
 puts "local variables in the block: #{local_variables.join ", "}"
end
end
puts "no local variables outside the block" if local_variables.empty?
puts "no local variables outside the block" if local_variables.empty?
</syntaxhighlight>وتكون النتيجة طباعة التالي:
</syntaxhighlight>وتكون النتيجة طباعة التالي:<syntaxhighlight lang="text">
 
local variables in the block: a
local variables in the block: a
no local variables outside the block
no local variables outside the block
</syntaxhighlight>


بما أنّ الكتلة البرمجيّة block تنشئ نطاقًا جديد فلن يكون من الممكن استخدام أي متغيّر محليّ يُنشَأ ضمن هذا النطاق في النطاقات الأخرى خارجه. لكن يُمكن للمتغيّرات المعرّفة في نطاق ما أن تُستخدم في النّطاقات الأخرى المتضمّنة فيه كالتّالي:<syntaxhighlight lang="ruby">
بما أنّ الكتلة البرمجيّة block تنشئ نطاقًا جديد فلن يكون من الممكن استخدام أي متغيّر محليّ يُنشَأ ضمن هذا النطاق في النطاقات الأخرى خارجه. لكن يُمكن للمتغيّرات المعرّفة في نطاق ما أن تُستخدم في النّطاقات الأخرى المتضمّنة فيه كالتّالي:<syntaxhighlight lang="ruby">
a = 0
a = 0
1.times do
1.times do
 puts "local variables: #{local_variables.join ", "}"
 puts "local variables: #{local_variables.join ", "}"
end
end
</syntaxhighlight>وتكون النتيجة طباعة التّالي:
</syntaxhighlight>وتكون النتيجة طباعة التّالي:<syntaxhighlight lang="text">
 
local variables: a
local variables: a
</syntaxhighlight>


ومن جهة أخرى، قد تودّ أن تعزل المتغيّرات المحليّة المعرّفة ضمن كتلة برمجيّة عن النّطاق الخارجيّ الذي يتضمنّها، في هذه الحالة عليك كتابة هذه المتغيّرات ضمن الكتلة البرمجيّة وكتابة فاصلة منقوطة بعد هذه المتغيّرات. لمثال على ذلك ارجع إلى التوثيق الخاص باستدعاء التوابع، واقرأ فقرة المتغيّرات المحليّة ضمن الكتل البرمجيّ.
ومن جهة أخرى، قد تودّ أن تعزل المتغيّرات المحليّة المعرّفة ضمن كتلة برمجيّة عن النّطاق الخارجيّ الذي يتضمنّها، في هذه الحالة عليك كتابة هذه المتغيّرات ضمن الكتلة البرمجيّة وكتابة فاصلة منقوطة بعد هذه المتغيّرات. لمثال على ذلك ارجع إلى التوثيق الخاص باستدعاء التوابع، واقرأ فقرة المتغيّرات المحليّة ضمن الكتل البرمجيّ.
سطر 50: سطر 42:
يُنشَأ المتغيّر المحليّ عندما يمرّ مُفسِّر اللّغة parser على عمليّة الإسناد، وليس عندما تقع هذه العمليّة بالفعل، كما في المثال التّالي:<syntaxhighlight lang="ruby">
يُنشَأ المتغيّر المحليّ عندما يمرّ مُفسِّر اللّغة parser على عمليّة الإسناد، وليس عندما تقع هذه العمليّة بالفعل، كما في المثال التّالي:<syntaxhighlight lang="ruby">
a = 0 if false # لا يحصل الإسناد هنا
a = 0 if false # لا يحصل الإسناد هنا
p local_variables # يطبع [:a]
p local_variables # يطبع [:a]
p a # يطبع nil
p a # يطبع nil
</syntaxhighlight>هذا التشابه بين أسماء المتغيّرات والتوابع قد يؤدّي في بعض الأحيان إلى صعوبة في فهم الشيفرة، فعلى سبيل المثال:<syntaxhighlight lang="ruby">
</syntaxhighlight>هذا التشابه بين أسماء المتغيّرات والتوابع قد يؤدّي في بعض الأحيان إلى صعوبة في فهم الشيفرة، فعلى سبيل المثال:<syntaxhighlight lang="ruby">
def big_calculation
def big_calculation
 42 # تظاهر بأنّها عمليّة تأخذ الكثير من الوقت
 42 # تظاهر بأنّها عمليّة تأخذ الكثير من الوقت
end
end
big_calculation = big_calculation()
big_calculation = big_calculation()
</syntaxhighlight>أيّ إشارة هنا إلى big_calculation ستُعدّ على أنّها متغيّر محليّ وسيُحتفَظ بها في الذاكرة المخبئة cache. وإذا أردت بدلًا من ذلك استدعاء التابع ذي الاسم نفسه فعليك أن تكتب self.big_calculatoin.
</syntaxhighlight>أيّ إشارة هنا إلى big_calculation ستُعدّ على أنّها متغيّر محليّ وسيُحتفَظ بها في الذاكرة المخبئة cache. وإذا أردت بدلًا من ذلك استدعاء التابع ذي الاسم نفسه فعليك أن تكتب self.big_calculatoin.
سطر 77: سطر 64:
وهذا مثال على استخدام متغيّرات الحالة:<syntaxhighlight lang="ruby">
وهذا مثال على استخدام متغيّرات الحالة:<syntaxhighlight lang="ruby">
class C
class C
 def initialize(value)
 def initialize(value)
   @instance_variable = value
   @instance_variable = value
 end
 end
 def value
 def value
   @instance_variable
   @instance_variable
 end
 end
end
end
object1 = C.new "some value"
object1 = C.new "some value"
object2 = C.new "other value"
object2 = C.new "other value"
p object1.value # تطبع "some value"
p object1.value # تطبع "some value"
p object2.value # تطبع "other value"
p object2.value # تطبع "other value"
</syntaxhighlight>متغيّرات الحالة التي لم يتمّ تهيئتها بقيمة ابتدائيّة تأخذ قيمة nil تلقائيًّا. وإذا شغّلتَ روبي بوضع تفعيل التحذيرات (warnings) فسيظهر لك تنبيهًا عند كلّ محاولة لاستخدام متغيّر حالة لم تتم تهيئته.
</syntaxhighlight>متغيّرات الحالة التي لم يتمّ تهيئتها بقيمة ابتدائيّة تأخذ قيمة nil تلقائيًّا. وإذا شغّلتَ روبي بوضع تفعيل التحذيرات (warnings) فسيظهر لك تنبيهًا عند كلّ محاولة لاستخدام متغيّر حالة لم تتم تهيئته.
سطر 110: سطر 86:
مثال:<syntaxhighlight lang="ruby">
مثال:<syntaxhighlight lang="ruby">
class A
class A
 @@class_variable = 0
 @@class_variable = 0
 def value
 def value
   @@class_variable
   @@class_variable
 end
 end
 def update
 def update
   @@class_variable = @@class_variable + 1
   @@class_variable = @@class_variable + 1
 end
 end
end
end
class B < A
class B < A
 def update
 def update
   @@class_variable = @@class_variable + 2
   @@class_variable = @@class_variable + 2
 end
 end
end
end
a = A.new
a = A.new
b = B.new
b = B.new
puts "A value: #{a.value}"
puts "A value: #{a.value}"
puts "B value: #{b.value}"
puts "B value: #{b.value}"
</syntaxhighlight>وعند تنفيذه يطبع التّالي:
</syntaxhighlight>وعند تنفيذه يطبع التّالي:<syntaxhighlight lang="text">
 
A value: 0
A value: 0
B value: 0
B value: 0
</syntaxhighlight>


وبالاستمرار مع نفس المثال، يمكننا تحديث قيمة المتغيّر باستخدام كائنٍ من أيّ من الصنفين، وستُشارك القيمة الجديدة بينهما:<syntaxhighlight lang="ruby">
وبالاستمرار مع نفس المثال، يمكننا تحديث قيمة المتغيّر باستخدام كائنٍ من أيّ من الصنفين، وستُشارك القيمة الجديدة بينهما:<syntaxhighlight lang="ruby">
puts "update A"
puts "update A"
a.update
a.update
puts "A value: #{a.value}"
puts "A value: #{a.value}"
puts "B value: #{b.value}"
puts "B value: #{b.value}"
puts "update B"
puts "update B"
b.update
b.update
puts "A value: #{a.value}"
puts "A value: #{a.value}"
puts "B value: #{b.value}"
puts "B value: #{b.value}"
puts "update A"
puts "update A"
a.update
a.update
puts "A value: #{a.value}"
puts "A value: #{a.value}"
puts "B value: #{b.value}"
puts "B value: #{b.value}"
</syntaxhighlight>وتكون النتيجة:
</syntaxhighlight>وتكون النتيجة:<syntaxhighlight lang="text">
 
update A
update A
A value: 1
A value: 1
B value: 1
B value: 1
update B
update B
A value: 3
A value: 3
B value: 3
B value: 3
update A
update A
A value: 4
A value: 4
B value: 4
B value: 4
</syntaxhighlight>


عند محاولة الوصول إلى متغيّر صنف لم تتمّ تهيئته فسيظهر استثناء من نوع NameError.
عند محاولة الوصول إلى متغيّر صنف لم تتمّ تهيئته فسيظهر استثناء من نوع NameError.
سطر 203: سطر 142:
مثال:<syntaxhighlight lang="ruby">
مثال:<syntaxhighlight lang="ruby">
$global = 0
$global = 0
class C
class C
 puts "in a class: #{$global}"
 puts "in a class: #{$global}"
 def my_method
 def my_method
   puts "in a method: #{$global}"
   puts "in a method: #{$global}"
   $global = $global + 1
   $global = $global + 1
   $other_global = 3
   $other_global = 3
 end
 end
end
end
C.new.my_method
C.new.my_method
puts "at top-level, $global: #{$global}, $other_global: #{$other_global}"
puts "at top-level, $global: #{$global}, $other_global: #{$other_global}"
</syntaxhighlight>والنتيجة:
</syntaxhighlight>والنتيجة:<syntaxhighlight lang="text">
 
in a class: 0
in a class: 0
in a method: 0
in a method: 0
at top-level, $global: 1, $other_global: 3
at top-level, $global: 1, $other_global: 3
</syntaxhighlight>


المتغيّرات العامّة التي لا يتم تهيئتها تكون قيمتها nil.
المتغيّرات العامّة التي لا يتم تهيئتها تكون قيمتها nil.
سطر 238: سطر 165:
يمكنك تعريف دوالّ تؤدّي دور عمليّة الإسناد كالتّالي:<syntaxhighlight lang="ruby">
يمكنك تعريف دوالّ تؤدّي دور عمليّة الإسناد كالتّالي:<syntaxhighlight lang="ruby">
class C
class C
 def value=(value)
 def value=(value)
   @value = value
   @value = value
 end
 end
end
end
c = C.new
c = C.new
c.value = 42
c.value = 42
</syntaxhighlight>استخدام هذه التوابع تجعل ببرنامجك يظهر بشكل أجمل. ومعظم المبرمجين يستخدمون Module#attr_accessor عند الإسناد إلى متحوّل حالة:<syntaxhighlight lang="ruby">
</syntaxhighlight>استخدام هذه التوابع تجعل ببرنامجك يظهر بشكل أجمل. ومعظم المبرمجين يستخدمون Module#attr_accessor عند الإسناد إلى متحوّل حالة:<syntaxhighlight lang="ruby">
سطر 258: سطر 179:
عند استخدام الإسناد باستخدام التوابع فمن اللازم وجود مستقبِل، وفي حال عدم وجوده فستفترض لغة روبي أنّك تقوم بالإسناد إلى متغيّر محليّ.<syntaxhighlight lang="ruby">
عند استخدام الإسناد باستخدام التوابع فمن اللازم وجود مستقبِل، وفي حال عدم وجوده فستفترض لغة روبي أنّك تقوم بالإسناد إلى متغيّر محليّ.<syntaxhighlight lang="ruby">
class C
class C
 attr_accessor :value
 attr_accessor :value
 def my_method
 def my_method
   value = 42
   value = 42
   puts "local_variables: #{local_variables.join ", "}"
   puts "local_variables: #{local_variables.join ", "}"
   puts "@value: #{@value.inspect}"
   puts "@value: #{@value.inspect}"
 end
 end
end
end
C.new.my_method
C.new.my_method
</syntaxhighlight>وتكون النتيجة طباعة التّالي:
</syntaxhighlight>وتكون النتيجة طباعة التّالي:<syntaxhighlight lang="text">
 
local_variables: value
local_variables: value
@value: nil
@value: nil
</syntaxhighlight>


لذلك فعند استخدام دوال الإسناد، عليك تحديد مستقبِل:<syntaxhighlight lang="ruby">
لذلك فعند استخدام دوال الإسناد، عليك تحديد مستقبِل:<syntaxhighlight lang="ruby">
class C
class C
 attr_accessor :value
 attr_accessor :value
 def my_method
 def my_method
   self.value = 42
   self.value = 42
   puts "local_variables: #{local_variables.join ", "}"
   puts "local_variables: #{local_variables.join ", "}"
   puts "@value: #{@value.inspect}"
   puts "@value: #{@value.inspect}"
 end
 end
end
end
C.new.my_method
C.new.my_method
</syntaxhighlight>وتكون النتيجة:
</syntaxhighlight>وتكون النتيجة:<syntaxhighlight lang="text">
 
local_variables:
local_variables:
@value: 42
@value: 42
</syntaxhighlight>


== الإسناد المختصر ==
== الإسناد المختصر ==
يمكنك الجمع بين أكثر من معامل مع عملية الإسناد، فعلى سبيل المثال، يمكنك عمل التّالي:<syntaxhighlight lang="ruby">
يمكنك الجمع بين أكثر من معامل مع عملية الإسناد، فعلى سبيل المثال، يمكنك عمل التّالي:<syntaxhighlight lang="ruby">
a = 1
a = 1
a += 2
a += 2
p a # تطبع 3
p a # تطبع 3
وهذا يكافئ:
وهذا يكافئ:
a = 1
a = 1
a = a + 2
a = a + 2
p a # تطبع 3
p a # تطبع 3
</syntaxhighlight>وعلى نفس المنوال، يمكنك استخدام هذه المعاملات أيضًا: +, -, *, /, %, **, &, |, ^, <<, >>
</syntaxhighlight>وعلى نفس المنوال، يمكنك استخدام هذه المعاملات أيضًا: +, -, *, /, %, **, &, |, ^, <<, >>
سطر 324: سطر 221:


مثال:<syntaxhighlight lang="ruby">
مثال:<syntaxhighlight lang="ruby">
a ||= 0
a ||= 0
 
a &&= 1
a &&= 1
p a # تطبع 1
p a # تطبع 1
 
</syntaxhighlight>لاحظ أنّ هذين المعاملين يكافئان a || a = 0 أكثر من a = a || 0
لاحظ أنّ هذين المعاملين يكافئان a || a = 0 أكثر من a = a || 0
</syntaxhighlight>


== إسناد المصفوفات ضمنيًّا ==
== إسناد المصفوفات ضمنيًّا ==
يمكنك إنشاء مصفوفة ضمن عمليّة الإسناد وذلك بكتابة العناصر متتالية يفصل بينها فواصل كالتّالي:<syntaxhighlight lang="ruby">
يمكنك إنشاء مصفوفة ضمن عمليّة الإسناد وذلك بكتابة العناصر متتالية يفصل بينها فواصل كالتّالي:<syntaxhighlight lang="ruby">
a = 1, 2, 3
a = 1, 2, 3
 
p a #[1, 2, 3] تطبع
p a # تطبع [1, 2, 3]
</syntaxhighlight>وهكذا يتمّ إنشاء مصفوفة ضمنيًّا.
</syntaxhighlight>وهكذا يتمّ إنشاء مصفوفة ضمنيًّا.


يمكنك استخدام الرمز * أو معامل "الفصل" لتفكيك مصفوفة أثناء عملية الإسناد. وهذا يشابه الإسناد المتعدد. مثال:<syntaxhighlight lang="ruby">
يمكنك استخدام الرمز * أو معامل "الفصل" لتفكيك مصفوفة أثناء عملية الإسناد. وهذا يشابه الإسناد المتعدد. مثال:<syntaxhighlight lang="ruby">
a = *[1, 2, 3]
a = *[1, 2, 3]
 
p a #[1, 2, 3] تطبع
p a # تطبع [1, 2, 3]
</syntaxhighlight>كما يمكنك الفصل في أيّ موضع على الجانب اليمينيّ من الإسناد:<syntaxhighlight lang="ruby">
</syntaxhighlight>كما يمكنك الفصل في أيّ موضع على الجانب اليمينيّ من الإسناد:<syntaxhighlight lang="ruby">
a = 1, *[2, 3]
a = 1, *[2, 3]
 
p a #[1, 2, 3] تطبع
p a # تطبع [1, 2, 3]
</syntaxhighlight>
</syntaxhighlight>


سطر 353: سطر 243:
يمكنك في لغة روبي أن تسند عدّة قيم على الجانب الأيمن إلى عدّة متغيّرات على الجانب الأيسر كالتّالي:<syntaxhighlight lang="ruby">
يمكنك في لغة روبي أن تسند عدّة قيم على الجانب الأيمن إلى عدّة متغيّرات على الجانب الأيسر كالتّالي:<syntaxhighlight lang="ruby">
a, b = 1, 2
a, b = 1, 2
 
p a: a, b: b #{:a=>1, :b=>2} تطبع
p a: a, b: b # تطبع {:a=>1, :b=>2}
</syntaxhighlight>وبنفس الطريقة يمكنك استخدام الإسناد المتعدّد مع أيّ نوع من المتغيّرات، سواء كانت متغيّرات أصناف أو متغيّرات حالة أو متغيرات عامّة، وحتّى الإسناد باستخدام التوابع كما في المثال:<syntaxhighlight lang="ruby">
</syntaxhighlight>وبنفس الطريقة يمكنك استخدام الإسناد المتعدّد مع أيّ نوع من المتغيّرات، سواء كانت متغيّرات أصناف أو متغيّرات حالة أو متغيرات عامّة، وحتّى الإسناد باستخدام التوابع كما في المثال:<syntaxhighlight lang="ruby">
def value=(value)
def value=(value)
 p assigned: value
 p assigned: value
end
end
 
self.value, $global = 1, 2 #{:assigned=>1} تطبع
self.value, $global = 1, 2 # تطبع {:assigned=>1}
 
p $global # تطبع 2
p $global # تطبع 2
</syntaxhighlight>كما يمكنك استخدام الإسناد المتعدّد للتّبديل بين قيمتي متغيّرين بشكل مباشر:<syntaxhighlight lang="ruby">
</syntaxhighlight>كما يمكنك استخدام الإسناد المتعدّد للتّبديل بين قيمتي متغيّرين بشكل مباشر:<syntaxhighlight lang="ruby">
old_value = 1
old_value = 1
new_value, old_value = old_value, 2
new_value, old_value = old_value, 2
p new_value: new_value, old_value: old_value
p new_value: new_value, old_value: old_value
 
#{:new_value=>1, :old_value=>2} تطبع
# تطبع {:new_value=>1, :old_value=>2}
</syntaxhighlight>في حال وجود عدد من القيم على الجانب الأيمن أكثر من عدد المتغيّرات المسند إليها على الجانب الأيسر، فعندها يتمّ تجاهل القيم الزائدة:<syntaxhighlight lang="ruby">
</syntaxhighlight>في حال وجود عدد من القيم على الجانب الأيمن أكثر من عدد المتغيّرات المسند إليها على الجانب الأيسر، فعندها يتمّ تجاهل القيم الزائدة:<syntaxhighlight lang="ruby">
a, b = 1, 2, 3
a, b = 1, 2, 3
 
p a: a, b: b #{:a=>1, :b=>2} تطبع
p a: a, b: b # تطبع {:a=>1, :b=>2}
</syntaxhighlight>يمكنك استخدام معامل الفصل * في الإسناد المتعدّد لتجمع عددًا من القيم في مصفوفة واحدة:<syntaxhighlight lang="ruby">
</syntaxhighlight>يمكنك استخدام معامل الفصل * في الإسناد المتعدّد لتجمع عددًا من القيم في مصفوفة واحدة:<syntaxhighlight lang="ruby">
a, *b = 1, 2, 3
a, *b = 1, 2, 3
 
p a: a, b: b #{:a=>1, :b=>[2, 3]} تطبع
p a: a, b: b # تطبع {:a=>1, :b=>[2, 3]}
</syntaxhighlight>ويمكنك وضع هذا المعامل في أيّ مكان على الجانب الأيسر:<syntaxhighlight lang="ruby">
</syntaxhighlight>ويمكنك وضع هذا المعامل في أيّ مكان على الجانب الأيسر:<syntaxhighlight lang="ruby">
*a, b = 1, 2, 3
*a, b = 1, 2, 3
 
p a: a, b: b #{:a=>[1, 2], :b=>3} تطبع
p a: a, b: b # تطبع {:a=>[1, 2], :b=>3}
</syntaxhighlight>لكن لا يمكنك استخدامه إلّا مرّة واحدة في كلّ عمليّة إسناد.
</syntaxhighlight>لكن لا يمكنك استخدامه إلّا مرّة واحدة في كلّ عمليّة إسناد.


سطر 390: سطر 269:
كما أنّه بإمكانك تفكيك المصفوفات عند تمرير القيم إلى التوابع، فكذلك بالإمكان تفكيك المصفوفة عند الإسناد وذلك باستخدام الأقواس المنحنية () كالتّالي:<syntaxhighlight lang="ruby">
كما أنّه بإمكانك تفكيك المصفوفات عند تمرير القيم إلى التوابع، فكذلك بالإمكان تفكيك المصفوفة عند الإسناد وذلك باستخدام الأقواس المنحنية () كالتّالي:<syntaxhighlight lang="ruby">
(a, b) = [1, 2]
(a, b) = [1, 2]
 
p a: a, b: b #{:a=>1, :b=>2} تطبع
p a: a, b: b # تطبع {:a=>1, :b=>2}
</syntaxhighlight>يمكنك أيضًا تفكيك المصفوفة ضمن عمليّة الإسناد المتعدّد:<syntaxhighlight lang="ruby">
</syntaxhighlight>يمكنك أيضًا تفكيك المصفوفة ضمن عمليّة الإسناد المتعدّد:<syntaxhighlight lang="ruby">
a, (b, c) = 1, [2, 3]
a, (b, c) = 1, [2, 3]
 
p a: a, b: b, c: c #{:a=>1, :b=>2, :c=>3} تطبع
p a: a, b: b, c: c # تطبع {:a=>1, :b=>2, :c=>3}
</syntaxhighlight>وبما أنّ عمليّة التفكيك تعتبر عمليّة إسناد متعدّد في حد ذاتها، فبالتالي يمكنك استخدام المعامل * ضمنها كالتّالي:<syntaxhighlight lang="ruby">
</syntaxhighlight>وبما أنّ عمليّة التفكيك تعتبر عمليّة إسناد متعدّد في حد ذاتها، فبالتالي يمكنك استخدام المعامل * ضمنها كالتّالي:<syntaxhighlight lang="ruby">
a, (b, *c), *d = 1, [2, 3, 4], 5, 6
a, (b, *c), *d = 1, [2, 3, 4], 5, 6
p a: a, b: b, c: c, d: d
p a: a, b: b, c: c, d: d
 
#{:a=>1, :b=>2, :c=>[3, 4], :d=>[5, 6]} تطبع
# تطبع {:a=>1, :b=>2, :c=>[3, 4], :d=>[5, 6]}
</syntaxhighlight>
</syntaxhighlight>



مراجعة 20:38، 15 نوفمبر 2018

الإسناد في لغة روبي

للإسناد في لغة روبي نستخدم رمز المساواة =، ففي المثال التّالي يُسنَد الرّقم 5 إلى المتغيّر المحلّي v:

v = 5

فالإسناد يُنشئ متغيّرًا محلّيًا جديدًا إذا لم يكن قد عُرِّفَ من قبل.

أسماء المتغيّرات المحليّة

اسم المتغيّر المحلّي يجب أن يبدأ بحرف صغير من مجموعة المحارف US-ASCII أو من مجموعة المحارف التي تُمثَّل باستخدام ثمان خانات ثنائيّة 8-bits. وبشكلٍ عام فإنّ أسماء المتغيّرات المحلّية متوافقة مع US-ASCII كون الأزرار التي تستخدم لكتابتها موجودة في جميع لوحات المفاتيح.

(عمومًا جميع البرامج المكتوبة بلغة روبي يجب أن تستخدم محارفًا متوافقة مع مجموعة المحارف US-ASCII. في مجموعات محارف كهذه، إذا كان البت الثامن بقيمة 1 فهذا يدلّ على أنّ المحرف ينتمي للمحارف الموسّعة extended character، ولغة روبي تسمح أن تحتوي أسماء المتغيّرات هذا النوع من المحارف.)

كما يُمكن لاسم المتحوّل أن يحتوي على حروفًا وأرقامًا ورمز الشرطة السفليّة underscore "_".

نطاق المتغيّرات المحليّة

بمجرّد أن يتمّ إسناد قيمة إلى المتغيّر المحلّيّ فكلّ استخدامات اسم هذا المتغيّر ضمن النطاق نفسه سيتمّ اعتبارها متغيّرات محليّة. وإليك هذا المثال:

1.times do
 a = 1
 puts "local variables in the block: #{local_variables.join ", "}"
end
puts "no local variables outside the block" if local_variables.empty?

وتكون النتيجة طباعة التالي:

local variables in the block: a
no local variables outside the block

بما أنّ الكتلة البرمجيّة block تنشئ نطاقًا جديد فلن يكون من الممكن استخدام أي متغيّر محليّ يُنشَأ ضمن هذا النطاق في النطاقات الأخرى خارجه. لكن يُمكن للمتغيّرات المعرّفة في نطاق ما أن تُستخدم في النّطاقات الأخرى المتضمّنة فيه كالتّالي:

a = 0
1.times do
 puts "local variables: #{local_variables.join ", "}"
end

وتكون النتيجة طباعة التّالي:

local variables: a

ومن جهة أخرى، قد تودّ أن تعزل المتغيّرات المحليّة المعرّفة ضمن كتلة برمجيّة عن النّطاق الخارجيّ الذي يتضمنّها، في هذه الحالة عليك كتابة هذه المتغيّرات ضمن الكتلة البرمجيّة وكتابة فاصلة منقوطة بعد هذه المتغيّرات. لمثال على ذلك ارجع إلى التوثيق الخاص باستدعاء التوابع، واقرأ فقرة المتغيّرات المحليّة ضمن الكتل البرمجيّ.

انظر أيضًا فقرة النواة-المتغيّرات المحليّة، لكن انتبه إلى أنّ الحلقات من نوع for لا تنشئ نطاقًا خاصًّا بها كما هو الحال في الكتل البرمجيّة.

التوابع والمتغيّرات المحليّة

أسماء المتغيّرات المحليّة والتوابع في لغة روبي متماثلة تقريبًا. فإذا عرّفت اسمًا دون أن تسندَ إليه أيّ قيمة فسيُعدّ في اللّغة على أنّه تابع. وبمجرّد أن تُسند إليه قيمة فسيُعدّ متغيّرًا.

يُنشَأ المتغيّر المحليّ عندما يمرّ مُفسِّر اللّغة parser على عمليّة الإسناد، وليس عندما تقع هذه العمليّة بالفعل، كما في المثال التّالي:

a = 0 if false # لا يحصل الإسناد هنا
p local_variables # يطبع [:a]
p a # يطبع nil

هذا التشابه بين أسماء المتغيّرات والتوابع قد يؤدّي في بعض الأحيان إلى صعوبة في فهم الشيفرة، فعلى سبيل المثال:

def big_calculation
 42 # تظاهر بأنّها عمليّة تأخذ الكثير من الوقت
end
big_calculation = big_calculation()

أيّ إشارة هنا إلى big_calculation ستُعدّ على أنّها متغيّر محليّ وسيُحتفَظ بها في الذاكرة المخبئة cache. وإذا أردت بدلًا من ذلك استدعاء التابع ذي الاسم نفسه فعليك أن تكتب self.big_calculatoin.

يمكنك أيضًا أن تُؤكّد على استدعاء التابع وذلك باستخدام أقواس فارغة كما يظهر في المثال، أو باستخدام مستقبِل محدّد مثل self. لكنّ الطّريقة الثّانية قد تسبب ظهور خطأ NameError إذا كان التابع غير متاح للاستدعاء العام (أي أنه ليس تابع عام).

وهناك حالة أخرى شائعة قد تسبّب التباسًا وتحصل عند استخدام if كالتّالي:

p a if a = 0.zero?

فبدلًا من طباعة "true" سيظهر خطأ NameError, undefined local variable or method 'a'. والسّبب في ذلك يعود إلى أنّ اللغة ترى المتغير a الذي قبل if أوّلًا قبل المتغير a الآخر وتحسب أنّك تريد استدعاء تابع، ثمّ إذا مرّت على المتغير a الآخر فستفترض أنّك تريد الإشارة إلى تابع محليّ.

هذا اللبس يحصل لأنّ تنفيذ العبارة البرمجيّة يحصل بعكس الترتيب المنشود، فالإسناد يتمّ أوّلًا ثمّ يحصل استدعاء لتابع غير موجود.

متغيّرات الحالة Instance Variables

وهي متغيّرات تُشارَك عبر كلّ التوابعّ التابعة لنفس الكائن. هذه المتغيّرات يجب أن تبدأ بالرّمز @، وعدا ذلك فهي تتبع نفس القواعد في تسميّة المتغيّرات المحليّة. وطالما أنّها تبدأ بالرّمز @ فيُمكن للحرف الثّاني أن يكون حرفًا كبيرًا (upper case).

وهذا مثال على استخدام متغيّرات الحالة:

class C
 def initialize(value)
   @instance_variable = value
 end
 def value
   @instance_variable
 end
end
object1 = C.new "some value"
object2 = C.new "other value"
p object1.value # تطبع "some value"
p object2.value # تطبع "other value"

متغيّرات الحالة التي لم يتمّ تهيئتها بقيمة ابتدائيّة تأخذ قيمة nil تلقائيًّا. وإذا شغّلتَ روبي بوضع تفعيل التحذيرات (warnings) فسيظهر لك تنبيهًا عند كلّ محاولة لاستخدام متغيّر حالة لم تتم تهيئته.

يمكن لتابع value أن يصل إلى القيمة التي ضُبِطَت في التابع initialize، وذلك فقط للكائن نفسه.

متغيّرات الأصناف Class Variables

وهي متغيّرات مشتركة بين الصنف والأصناف المتفرّعة منه والكائنات المتولّدة عنه.

يجب أن يبدأ متغيّر الصنف بالرمزين @@، وتتمة الاسم تتبع لنفس أسلوب تسمية متغيّرات الحالة.

مثال:

class A
 @@class_variable = 0
 def value
   @@class_variable
 end
 def update
   @@class_variable = @@class_variable + 1
 end
end
class B < A
 def update
   @@class_variable = @@class_variable + 2
 end
end
a = A.new
b = B.new
puts "A value: #{a.value}"
puts "B value: #{b.value}"

وعند تنفيذه يطبع التّالي:

A value: 0
B value: 0

وبالاستمرار مع نفس المثال، يمكننا تحديث قيمة المتغيّر باستخدام كائنٍ من أيّ من الصنفين، وستُشارك القيمة الجديدة بينهما:

puts "update A"
a.update
puts "A value: #{a.value}"
puts "B value: #{b.value}"
puts "update B"
b.update
puts "A value: #{a.value}"
puts "B value: #{b.value}"
puts "update A"
a.update
puts "A value: #{a.value}"
puts "B value: #{b.value}"

وتكون النتيجة:

update A
A value: 1
B value: 1
update B
A value: 3
B value: 3
update A
A value: 4
B value: 4

عند محاولة الوصول إلى متغيّر صنف لم تتمّ تهيئته فسيظهر استثناء من نوع NameError.

لاحظ أنّ الأصناف لديها أيضًا متغيّرات حالة وذلك لأنّ الأصناف هي كائنات كذلك، لذلك حاول ألّا تخلط بين متغيّرات الأصناف ومتغيّرات الحالة.

المتغيّرات العامّة Global Variables

المتغيّرات العامّة يمكن الوصول إليها في كلّ مكان وهي تبدأ بالرّمز $ وباقي الاسم يتبع نفس أسلوب تسمية متغيّرات الحالة.

مثال:

$global = 0
class C
 puts "in a class: #{$global}"
 def my_method
   puts "in a method: #{$global}"
   $global = $global + 1
   $other_global = 3
 end
end
C.new.my_method
puts "at top-level, $global: #{$global}, $other_global: #{$other_global}"

والنتيجة:

in a class: 0
in a method: 0
at top-level, $global: 1, $other_global: 3

المتغيّرات العامّة التي لا يتم تهيئتها تكون قيمتها nil.

هناك بعض المتغيّرات العامّة المعرّفة مسبقًا في لغة روبي والتي قد تؤدّي أدوارًا مختلفة حسب السّياق كما هو الحال بالنّسبة لمتغيّرات المطابقة في التعابير النمطية (regular expressions)، وأحيانًا يكون لهذه المتغيّرات العامّة تأثيرات جانبيّة عندما يتمّ الإسناد إليها. لمزيد من التّفاصيل راجع الدّليل الخاص بالمتغيّرات العامّة.

دوالّ الإسناد

يمكنك تعريف دوالّ تؤدّي دور عمليّة الإسناد كالتّالي:

class C
 def value=(value)
   @value = value
 end
end
c = C.new
c.value = 42

استخدام هذه التوابع تجعل ببرنامجك يظهر بشكل أجمل. ومعظم المبرمجين يستخدمون Module#attr_accessor عند الإسناد إلى متحوّل حالة:

class C
  attr_accessor :value
end

عند استخدام الإسناد باستخدام التوابع فمن اللازم وجود مستقبِل، وفي حال عدم وجوده فستفترض لغة روبي أنّك تقوم بالإسناد إلى متغيّر محليّ.

class C
 attr_accessor :value
 def my_method
   value = 42
   puts "local_variables: #{local_variables.join ", "}"
   puts "@value: #{@value.inspect}"
 end
end
C.new.my_method

وتكون النتيجة طباعة التّالي:

local_variables: value
@value: nil

لذلك فعند استخدام دوال الإسناد، عليك تحديد مستقبِل:

class C
 attr_accessor :value
 def my_method
   self.value = 42
   puts "local_variables: #{local_variables.join ", "}"
   puts "@value: #{@value.inspect}"
 end
end
C.new.my_method

وتكون النتيجة:

local_variables:
@value: 42

الإسناد المختصر

يمكنك الجمع بين أكثر من معامل مع عملية الإسناد، فعلى سبيل المثال، يمكنك عمل التّالي:

a = 1
a += 2
p a # تطبع 3
وهذا يكافئ:
a = 1
a = a + 2
p a # تطبع 3

وعلى نفس المنوال، يمكنك استخدام هذه المعاملات أيضًا: +, -, *, /, %, **, &, |, ^, <<, >>

ومن الممكن أيضًا استخدام  =|| وفي هذه الحالة يتمّ الإسناد فقط إذا كانت القيمة nil أو false، وبالمثل يمكن استخدام =&& فيتمّ الإسناد فقط إذا لم تكن القيمة nil أو false.

مثال:

a ||= 0
a &&= 1
p a # تطبع 1

لاحظ أنّ هذين المعاملين يكافئان a || a = 0 أكثر من a = a || 0

إسناد المصفوفات ضمنيًّا

يمكنك إنشاء مصفوفة ضمن عمليّة الإسناد وذلك بكتابة العناصر متتالية يفصل بينها فواصل كالتّالي:

a = 1, 2, 3
p a #[1, 2, 3] تطبع

وهكذا يتمّ إنشاء مصفوفة ضمنيًّا. يمكنك استخدام الرمز * أو معامل "الفصل" لتفكيك مصفوفة أثناء عملية الإسناد. وهذا يشابه الإسناد المتعدد. مثال:

a = *[1, 2, 3]
p a #[1, 2, 3] تطبع

كما يمكنك الفصل في أيّ موضع على الجانب اليمينيّ من الإسناد:

a = 1, *[2, 3]
p a #[1, 2, 3] تطبع

الإسناد المتعدّد

يمكنك في لغة روبي أن تسند عدّة قيم على الجانب الأيمن إلى عدّة متغيّرات على الجانب الأيسر كالتّالي:

a, b = 1, 2
p a: a, b: b #{:a=>1, :b=>2} تطبع

وبنفس الطريقة يمكنك استخدام الإسناد المتعدّد مع أيّ نوع من المتغيّرات، سواء كانت متغيّرات أصناف أو متغيّرات حالة أو متغيرات عامّة، وحتّى الإسناد باستخدام التوابع كما في المثال:

def value=(value)
 p assigned: value
end
self.value, $global = 1, 2 #{:assigned=>1} تطبع 
p $global # تطبع 2

كما يمكنك استخدام الإسناد المتعدّد للتّبديل بين قيمتي متغيّرين بشكل مباشر:

old_value = 1
new_value, old_value = old_value, 2
p new_value: new_value, old_value: old_value
#{:new_value=>1, :old_value=>2} تطبع

في حال وجود عدد من القيم على الجانب الأيمن أكثر من عدد المتغيّرات المسند إليها على الجانب الأيسر، فعندها يتمّ تجاهل القيم الزائدة:

a, b = 1, 2, 3
p a: a, b: b #{:a=>1, :b=>2} تطبع

يمكنك استخدام معامل الفصل * في الإسناد المتعدّد لتجمع عددًا من القيم في مصفوفة واحدة:

a, *b = 1, 2, 3
p a: a, b: b #{:a=>1, :b=>[2, 3]} تطبع

ويمكنك وضع هذا المعامل في أيّ مكان على الجانب الأيسر:

*a, b = 1, 2, 3
p a: a, b: b #{:a=>[1, 2], :b=>3} تطبع

لكن لا يمكنك استخدامه إلّا مرّة واحدة في كلّ عمليّة إسناد.

تفكيك المصفوفات

كما أنّه بإمكانك تفكيك المصفوفات عند تمرير القيم إلى التوابع، فكذلك بالإمكان تفكيك المصفوفة عند الإسناد وذلك باستخدام الأقواس المنحنية () كالتّالي:

(a, b) = [1, 2]
p a: a, b: b #{:a=>1, :b=>2} تطبع

يمكنك أيضًا تفكيك المصفوفة ضمن عمليّة الإسناد المتعدّد:

a, (b, c) = 1, [2, 3]
p a: a, b: b, c: c #{:a=>1, :b=>2, :c=>3} تطبع

وبما أنّ عمليّة التفكيك تعتبر عمليّة إسناد متعدّد في حد ذاتها، فبالتالي يمكنك استخدام المعامل * ضمنها كالتّالي:

a, (b, *c), *d = 1, [2, 3, 4], 5, 6
p a: a, b: b, c: c, d: d
#{:a=>1, :b=>2, :c=>[3, 4], :d=>[5, 6]} تطبع

مصادر