2013-01-20 24 views
5

के साथ कक्षा में रूबी instance_eval instance_eval और class_eval के बीच मूल अंतर को समझता हूं। जब मैंने चारों ओर खेलना शुरू किया है, तो मुझे कुछ पता चला है जिसमें attr_accessor शामिल है।attr_accessor

A = Class.new 
A.class_eval{ attr_accessor :x } 

a = A.new 
a.x = "x" 
a.x 
=> "x" # ... expected 

A.instance_eval{ attr_accessor :y } 

A.y = "y" 
=> NoMethodError: undefined method `y=' for A:Class 

a.y = "y" 
=> "y"  # WHATTT? 

कैसे यह है कि है: यहाँ एक उदाहरण है

  1. instance_eval हमारे एक वर्ग पर एक्सेसर में नहीं था (वस्तु)
  2. यह तो वास्तव में यह एक के उदाहरण पर जोड़ा ?

उत्तर

5

सबसे पहले, अपनी समझ (या अंतर्ज्ञान) सही है, तरीकों #instance_eval अंदर परिभाषित और #class_eval ही

A = Class.new 

A.instance_eval { def defined_in_instance_eval; :instance_eval; end } 
A.class_eval { def defined_in_class_eval; :class_eval; end } 

A.new.defined_in_class_eval # => :class_eval 
A.defined_in_instance_eval # => :instance_eval 

एक पक्ष टिप्पणी नहीं कर रहे हैं: जबकि self दोनों instance_eval और class_eval, में एक ही है डिफ़ॉल्ट definee अलग है, को देखने के http://yugui.jp/articles/846

क्या वास्तव में काम कर देता है Module#attr_accessor ही है, पर देखने के है इसकी परिभाषा: http://rxr.whitequark.org/mri/source/vm_method.c#620

यह def का उपयोग नहीं करता है, यह प्रसंग, self या एक डिफ़ॉल्ट definee पढ़ा नहीं है। यह सिर्फ मॉड्यूल में "मैन्युअल रूप से" विधियों को सम्मिलित करता है। यही कारण है कि परिणाम counterintuitive है।

0

विधि attr_accessor एक वर्ग विधि ऐसी है कि, जब एक वर्ग की शरीर में कहा जाता है, तो accessor तरीकों उदाहरणों उस वर्ग के पर निर्धारित किए जाते हैं।

जब आप A.class_eval{...} करते हैं, आप इसे एक वर्गA की शरीर भीतर, बुला रहे हैं इसलिए इसकी उदाहरणों ऐसे a रूप accessors सौंपा है।

जब आप A.instance_eval{...} करते हैं, आप एक वर्गA के गैर शरीर भीतर बुला इसलिए इसके उदाहरणों accessors निर्दिष्ट नहीं किए जाते।

आप Class.class_eval{attr_accessor :z} करते हैं, तो आप इसे एक वर्गClass की शरीर के भीतर, बुला रहे हैं तो इस तरह के A के रूप में अपनी उदाहरणों आवंटित किया जाएगा accessors: A.z = ...। तथ्य यह है कि आम तौर पर instance_eval बनाता है के बावजूद, आप बी के साथ देख सकते हैं

A.instance_methods : ["barx", "foox", "x", "x="] 
A.singleton_methods : [] 
B.instance_methods : ["fooy", "y", "y="] 
B.singleton_methods : ["bary"] 
C.instance_methods : [] 
C.singleton_methods : ["z", "z=", "fooz"] 
singleton_class.barz : where is barz ? 
singleton_class.methods : ["barz"] 

:

2

class_eval और instance_eval के बीच अंतर के लिए, Dynamically creating class method

class A; end 
A.class_eval do 
    attr_accessor :x 
    def barx; end 
    define_method :foox do; end 
end 

print 'A.instance_methods : '; p A.instance_methods(false).sort 
print 'A.singleton_methods : '; p A.singleton_methods 

class B; end 
B.instance_eval do 
    attr_accessor :y 
    def bary; end 
    define_method :fooy do; end 
end 

print 'B.instance_methods : '; p B.instance_methods(false).sort 
print 'B.singleton_methods : '; p B.singleton_methods 

class C; end 
singleton_class = class << C; self end 
singleton_class.instance_eval do 
    attr_accessor :z 
    def barz; puts 'where is barz ?' end 
    define_method :fooz do; end 
end 

print 'C.instance_methods : '; p C.instance_methods(false).sort 
print 'C.singleton_methods : '; p C.singleton_methods 

print 'singleton_class.barz : '; singleton_class.barz 
print 'singleton_class.methods : '; p singleton_class.methods(false) 

आउटपुट (रूबी 1.8.6) को देखने के सिंगलटन विधियों, स्पष्ट रूप से attr_accessor और define_method उदाहरण विधियों की परिभाषा को बल देते हैं।

+0

जो गड़बड़ है। महान उदाहरण @ डैनियल_वर्तानोव का जवाब वास्तव में बताता है कि क्यों 'attr_accessor' स्वयं पर लागू नहीं होता है, लेकिन यह वर्णन करने का एक शानदार तरीका है कि प्रत्येक प्रकार की विधि def'n के साथ क्या होता है। बहुत बहुत धन्यवाद। – brad

0
A.singleton_class.class_eval { attr_accessor :y } 
A.y = 'y' 
A.y