روبي:إضافة خصائص مخصصة إلى المدمج في الطبقات
-
25-09-2019 - |
سؤال
السؤال: باستخدام روبي أنها بسيطة لإضافة العرف طرق إلى الفئات الموجودة ، ولكن كيف يمكنك إضافة مخصص خصائص?هنا هو مثال على ما أحاول القيام به:
myarray = Array.new();
myarray.concat([1,2,3]);
myarray._meta_ = Hash.new(); # obviously, this wont work
myarray._meta_['createdby'] = 'dreftymac';
myarray._meta_['lastupdate'] = '1993-12-12';
## desired result
puts myarray._meta_['createdby']; #=> 'dreftymac'
puts myarray.inspect() #=> [1,2,3]
الهدف هو بناء تعريف الفئة في مثل هذه الطريقة أن الأشياء التي لا تعمل في المثال أعلاه سوف تعمل كما هو متوقع.
تحديث: (توضيح السؤال) أحد جوانب هذا من السؤال الأصلي:كما هدف إلى إضافة "القيم الافتراضية" التي عادة تكون في تهيئة طريقة الطبقة.
تحديث: (لماذا تفعل هذا) عادة, أنها بسيطة جدا فقط إنشاء فئة مخصصة يرث من مجموعة (أو أيا كان المدمج في فئة تريد لمحاكاة).هذا السؤال مستمد من بعض "اختبار فقط" رمز وليس محاولة تجاهل هذا مقبول عموما النهج.
المحلول
يذكر أن روبي لم يكن لديك الوصول إلى سمات (المتغيرات سبيل المثال) خارج تلك الحالة.لديك فقط الوصول إلى مثيل العامة الأساليب.
يمكنك استخدام attr_accessor
لإنشاء طريقة فئة بمثابة الملكية كما ذكرت:
irb(main):001:0> class Array
irb(main):002:1> attr_accessor :_meta_
irb(main):003:1> end
=> nil
irb(main):004:0>
irb(main):005:0* x = [1,2,3]
=> [1, 2, 3]
irb(main):006:0> x._meta_ = Hash.new
=> {}
irb(main):007:0> x._meta_[:key] = 'value'
=> "value"
irb(main):008:0>
على طريقة بسيطة للقيام الافتراضي التهيئة من أجل استرجاع قيمة, سوف تحتاج إلى الأساس reimplement attr_accessor
أنفسنا:
class Class
def attr_accessor_with_default accessor, default_value
define_method(accessor) do
name = "@#{accessor}"
instance_variable_set(name, default_value) unless instance_variable_defined?(name)
instance_variable_get(name)
end
define_method("#{accessor}=") do |val|
instance_variable_set("@#{accessor}", val)
end
end
end
class Array
attr_accessor_with_default :_meta_, {}
end
x = [1,2,3]
x._meta_[:key] = 'value'
p x._meta_
y = [4,5,6]
y._meta_[:foo] = 'bar'
p y._meta_
ولكن الانتظار!الإخراج غير صحيح:
{:key=>"value"}
{:foo=>"bar", :key=>"value"}
قمنا بإنشاء الإغلاق حول القيمة الافتراضية الحرفي التجزئة.
أفضل طريقة قد تكون ببساطة استخدام كتلة:
class Class
def attr_accessor_with_default accessor, &default_value_block
define_method(accessor) do
name = "@#{accessor}"
instance_variable_set(name, default_value_block.call) unless instance_variable_defined?(name)
instance_variable_get(name)
end
define_method("#{accessor}=") do |val|
instance_variable_set("@#{accessor}", val)
end
end
end
class Array
attr_accessor_with_default :_meta_ do Hash.new end
end
x = [1,2,3]
x._meta_[:key] = 'value'
p x._meta_
y = [4,5,6]
y._meta_[:foo] = 'bar'
p y._meta_
الآن الإخراج هو الصحيح لأن Hash.new
يسمى كل مرة القيمة الافتراضية هي استرجاع, بدلا من إعادة استخدام نفس الحرفي تجزئة في كل مرة.
{:key=>"value"}
{:foo=>"bar"}
نصائح أخرى
أليس خاصية مجرد getter و setter؟ إذا كان الأمر كذلك ، فلا يمكنك فعل ذلك:
class Array
# Define the setter
def _meta_=(value)
@_meta_ = value
end
# Define the getter
def _meta_
@_meta_
end
end
ثم ، يمكنك القيام:
x = Array.new
x._meta_
# => nil
x._meta_ = {:name => 'Bob'}
x._meta_
# => {:name => 'Bob'}
هل هذا يساعد؟