2010-02-10 15 views
15

मेरे पास एक कक्षा और हैश है। विधि के नाम के साथ कुंजी के साथ कक्षा में विधियों को गतिशील रूप से कैसे बनने के लिए हैश के सदस्यों को मैं कैसे प्राप्त कर सकता हूं?मैं कक्षा में विधियों के रूप में हैश कुंजी का उपयोग कैसे करूं?

class User 
    def initialize 
    @attributes = {"sn" => "Doe", "givenName" => "John"} 
    end 
end 

उदाहरण के लिए, मैं निम्नलिखित उत्पादन Doe करने में सक्षम होना चाहते हैं:

u = User.new 
puts u.sn 
+4

OpenStruct (मानक पुस्तकालय में struct.rb) को देखने के लिए सुनिश्चित करें। यह आप जो पूछ रहे हैं उससे थोड़ा अलग है: यह ओपनस्ट्रक्चर पर किसी भी विधि कॉल को एक्सेसर होने की अनुमति देता है, चाहे वह पहले ही परिभाषित हो या नहीं। लेकिन यह कोड है जिसे आपको लिखना नहीं है, जो कभी-कभी प्लस हो सकता है। –

उत्तर

14
def method_missing(name, *args, &blk) 
    if args.empty? && blk.nil? && @attributes.has_key?(name) 
    @attributes[name] 
    else 
    super 
    end 
end 

स्पष्टीकरण: यदि आप एक विधि है, जो मौजूद नहीं है, method_missing साथ शुरू हो जाती है, तो फोन विधि के नाम को पहले पैरामीटर के रूप में, विधि को दिए गए तर्कों और ब्लॉक को दिए जाने पर ब्लॉक के बाद।

उपर्युक्त में हम कहते हैं कि यदि कोई विधि, जिसे परिभाषित नहीं किया गया था, बिना तर्क के और बिना किसी ब्लॉक के कहा जाता है और हैश के पास विधि नाम के साथ एक प्रविष्टि है, तो वह उस प्रविष्टि का मान वापस कर देगी। अन्यथा यह सामान्य रूप से आगे बढ़ेगा।

+0

मुझे इसे बदलने के लिए जोड़ना था: name.to_s दोनों जगहों पर, लेकिन यह मुझे मिला जहां मैं चाहता था! धन्यवाद :) – Michael

+0

ओह, ठीक है, मैंने नहीं देखा कि आप हैश कुंजी के रूप में तारों का उपयोग कर रहे थे। – sepp2k

+0

इसके अलावा, आपको मिलान करने के लिए 'responds_to?' को ओवरराइड करना चाहिए, क्योंकि आपकी कक्षा अब उस विशेष संदेश का "जवाब" देती है। –

4

sepp2k द्वारा समाधान जाने का तरीका है। एक

class User 
    def initialize 
    @attributes = {"sn" => "Doe", "givenName" => "John"} 
    @attributes.each do |k,v| 
     self.class.send :define_method, k do v end 
    end 
    end 
end 

User.new.givenName # => "John" 

यह अग्रिम में सभी तरीकों उत्पन्न करता है ...

3
असल

severin है: हालांकि, अगर आपकी @attributes कभी नहीं आरंभीकरण के बाद बदल सकते हैं और आप गति की जरूरत है, तो आप इसे इस तरह से कर सकता है बेहतर विचार, सिर्फ इसलिए कि method_missing का उपयोग एक बुरा अभ्यास है, हर समय नहीं, लेकिन इसमें से अधिकांश।

severin द्वारा प्रदान किए गए कोड के साथ एक समस्या: यह प्रारंभिककर्ता को पास किया गया मान देता है, इसलिए आप इसे बदल नहीं सकते हैं। मैं तुम्हें एक छोटे से अलग दृष्टिकोण का सुझाव:

class User < Hash 
    def initialize(attrs) 
    attrs.each do |k, v| 
     self[k] = v 
    end 
    end 

    def []=(k, v) 
    unless respond_to?(k) 
     self.class.send :define_method, k do 
     self[k] 
     end 
    end 

    super 
    end 
end 

चलो यह जाँच:

u = User.new(:name => 'John') 
p u.name 
u[:name] = 'Maria' 
p u.name 

और यह भी आप Struct के साथ यह कर सकते हैं:

attrs = {:name => 'John', :age => 22, :position => 'developer'} 
keys = attrs.keys 

user = Struct.new(*keys).new(*keys.map { |k| attrs[k] }) 

चलें परीक्षण:

p user 
p user.name 
user[:name] = 'Maria' 
p user.name 
user.name = 'Vlad' 
p user[:name] 

या यहां तक ​​कि ओपनस्ट्रक्चर, लेकिन सीए यह विधि नहीं बनाएगा, यदि वह पहले उदाहरण के तरीकों में यह राशि REFUL, आप OpenStruct.instance_methods का उपयोग करके कि लिए देख सकते हैं (प्रकार की वजह से, मैं अब दूसरा दृष्टिकोण का उपयोग कर रहा प्रयोग किया जाता है):

attrs = {:name => 'John', :age => 22, :position => 'developer'} 
user = OpenStruct.new(attrs) 

हां, इतना आसान :

user.name 
user[:name] # will give you an error, because OpenStruct isn't a Enumerable or Hash 
+0

आपकी व्याख्या और विस्तारित उदाहरण वास्तव में महान है। धन्यवाद! –

29

बस OpenStruct का उपयोग करें:

require 'ostruct' 
class User < OpenStruct 
end 

u = User.new :sn => 222 
u.sn 
1

आप इस के लिए ActiveResource "उधार" कर सकते हैं।

require 'active_resource' 
class User < ActiveResource::Base 
    self.site = '' # must be a string 
end 

उपयोग::

u = User.new "sn" => "Doe", "givenName" => "John", 'job'=>{'description'=>'Engineer'} 
u.sn # => "Doe" 
u.sn = 'Deere' 
u.job.description # => "Engineer" 
# deletion 
u.attributes.delete('givenName') 

ध्यान दें कि यू यह भी नेस्टेड हैश और काम संभालती है।नौकरी एक उपयोगकर्ता है :: नौकरी - यह वर्ग स्वतः निर्मित है। घोंसला वाले मूल्य को असाइन करते समय एक गोचाचा जाता है। तुम सिर्फ एक हैश असाइन नहीं कर सकते, लेकिन उचित वर्ग में लपेट चाहिए:

u.job = User::Job.new 'foo' => 'bar' 
u.job.foo # => 'bar 

दुर्भाग्य से, जब आप एक नेस्टेड हैश है कि एक इसी वर्ग नहीं है जोड़ना चाहते हैं, यह भद्दा है क्योंकि आप के लिए है बल एरेस हैश से वर्ग बनाने के लिए:

# assign the hash first 
u.car = {'make' => 'Ford'} 
# force refresh - this can be put into a method 
u = User.new Hash.from_xml(u.to_xml).values.first 
संबंधित मुद्दे

 संबंधित मुद्दे