2011-03-31 6 views
11

मैं उम्मीद के रूप में निम्नलिखित कोड काम करने की उम्मीद में शामिल कर सकता है, लेकिन यह मेरे लिए एक NoMethodError (निजी विधि `foo '# < MyClass ... के लिए कहा जाता है)मैं गतिशील रूप से एक attr_reader

class MyClass 
end 

my_object = MyClass.new 

my_object.instance_variable_set(:@foo, "bar") 
MyClass.send("attr_reader", :foo) 

puts my_object.foo 

समस्या है देता है मैं एक बड़े आवेदन में शाब्दिक रूप से समान कोड का उपयोग कर रहा हूं और यह ठीक वैसे ही काम करता है जैसा मैं उम्मीद करता हूं, लेकिन जब मैं इसे सबसे बुनियादी उदाहरण में सरल बनाता हूं तो यह विफल हो जाता है।

(मैं समझता हूँ वहाँ मैं रूबी में क्या कर रहा करने के लिए कई अन्य तरीके हैं)

+1

उदाहरण आईआरबी में काम करता है, लेकिन गहरे लाल रंग नहीं ... –

+0

@jleedev जोड़ने के लिए instance_eval का उपयोग करें - मैं एक ही बात पाया (रूबी 1.8.6 और रूबी उद्यम 1.8.7 में दोनों)। irb बहुत अच्छा है, लेकिन यदि आप एक फ़ाइल से सटीक वही आदेश चलाते हैं ... क्या आपको लगता है कि यह रूबी कार्यान्वयन में एक बग है (आरईई ज्यादातर कचरा कलेक्टर को सिर्फ लालसा)? –

उत्तर

0

बस सार्वजनिक बनने के लिए विधि के लिए मजबूर:

MyClass.send("public", :foo) 

मुझे पता नहीं क्यों यह में निजी है कुछ मामले।

+0

यह मानता है कि 'foo' विधि पहले से ही परिभाषित कर दी गई है, जो कि कुछ आवृत्ति चर के लिए मामला नहीं हो सकता है। – Phrogz

+0

यह अब तक का सबसे अच्छा जवाब है, लेकिन मैं अभी भी उत्सुक हूं कि यह कुछ मामलों में निजी क्यों है और दूसरों को नहीं। – Leroy22

3

दिलचस्प समस्या, मैंने पाया इस समाधान ठीक काम करता है:

MyClass.class_eval("attr_reader :foo") 
+0

मैं स्ट्रिंग फॉर्म की बजाय ब्लॉक फॉर्म (प्रति @ माइकलवाइस 'उत्तर) का उपयोग करने की अनुशंसा करता हूं ताकि कोई रनटाइम पार्सिंग/लेक्सिंग की आवश्यकता न हो। – Phrogz

+0

हां, आप सही हैं, मैंने अभी बेहतर तरीके से खोज किए बिना इस कामकाजी समाधान को तुरंत पाया है। –

5

उपयोग Module#class_eval:

ऐसा करने से, ब्लॉक MyClass के संदर्भ में डालता है, इस प्रकार आप attr_reader

कॉल करने के लिए अनुमति देता है
ruby-1.9.2-p136 :028 > my_object.instance_variable_set(:@foo, "bar") 
=> "bar" 
ruby-1.9.2-p136 :029 > MyClass.class_eval{attr_reader :foo} 
=> nil 
ruby-1.9.2-p136 :030 > my_object.foo 
=> "bar" 
+0

मुझे आश्चर्य है कि कोई कक्षा के एक विशेष उदाहरण के लिए ऐसा करने में सक्षम है। –

1

@ माइकलेविस द्वारा उत्तर अच्छा है, लेकिन कक्षा को फिर से क्यों नहीं खोलें?

irb(main):001:0> class MyClass; end 
#=> nil 
irb(main):002:0> m = MyClass.new 
#=> #<MyClass:0x2d43ae0> 
irb(main):003:0> class MyClass; attr_accessor :foo; end 
#=> nil 
irb(main):004:0> m.foo = 42 
#=> 42 
+0

यदि यह एक मणि है जिसे आप ट्वीव कर रहे हैं: 'क्लास मॉड्यूलनाम; end' कारणों: लेखन त्रुटि: ModuleName एक वर्ग \t (आईआरबी) से नहीं है: 15 \t/usr/bin/आईआरबी से: 12: में '

'' – Crisfole

+0

@Crisfole शायद इसलिए कि यह एक 'module' एक वर्ग के बजाय। – Phrogz

+0

मुझे एक मणि मिश्रण होना चाहिए था। मैंने सोचा कि मैं इसे फिर से खोलने की कोशिश कर रहा था -> https://github.com/dcparker/ruby-gmail/blob/master/lib/gmail.rb#L3-L6। शायद मैं बंडलर चलाने के लिए भूल गया .... – Crisfole

1

के एक पल है कि आप वर्ग (जो मुझे लगता है की उस विशेष उदाहरण के लिए एक्सेसर बनाना चाहते हैं के लिए मान लेते हैं मामले के बाद से आप उदाहरण पर काम कर रहे हैं है।

आप बस खोल सकते हैं उदाहरण के सिंगलटन वर्ग और एक्सेसर

class MyClass 
end 
my_instance = MyClass.new 
my_instance.singleton_class.instance_eval { attr_accessor :foo } 
my_instance.foo = :bar 
my_instance.foo # => :bar 
संबंधित मुद्दे