سؤال

السؤال: باستخدام روبي أنها بسيطة لإضافة العرف طرق إلى الفئات الموجودة ، ولكن كيف يمكنك إضافة مخصص خصائص?هنا هو مثال على ما أحاول القيام به:

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'}

هل هذا يساعد؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top