2010-11-22 19 views
5

मैं PHP dev हूं और फिलहाल मैं रेल (3) और निश्चित रूप से - रूबी सीख रहा हूं। I don't want to believe in magic और इसलिए मैं उन चीज़ों के बारे में जितना समझ सकता हूं जो रेल के पीछे "पीछे" होते हैं। जो मैंने दिलचस्प पाया वह एक्टिव रिकार्ड मॉडल में has_one या belongs_to जैसी विधि कॉल करता है।रेल्स विधि "has_one" काम की तरह कैसे कॉल करती है?

मुझे लगता है कि पुन: पेश करने की कोशिश की, और अनुभवहीन उदाहरण के साथ आया था: "यह काम करेगा"

# has_one_test_1.rb 
module Foo 
    class Base 
    def self.has_one 
     puts 'Will it work?' 
    end 
    end 
end 

class Model2 < Foo::Base 
    has_one 
end 

बस इस फाइल चल उत्पादन होगा, जैसा कि मैंने उम्मीद की थी।

रेल स्रोत के माध्यम से खोज करते समय मुझे जिम्मेदार कार्य मिला: def has_one(association_id, options = {})

यह कैसे हो सकता है, क्योंकि यह स्पष्ट रूप से एक उदाहरण (?) है और क्लास विधि नहीं है, इसे काम नहीं करना चाहिए।

# has_one_test_2.rb 
module Foo 
    module Bar 
    module Baz 
     def has_one stuff 
     puts "I CAN HAS #{stuff}?" 
     end 
    end 
    def self.included mod 
     mod.extend(Baz) 
    end 
    end 
    class Base 
    include Bar 
    end 
end 

class Model < Foo::Base 
    has_one 'CHEEZBURGER' 
end 

अब चल has_one_test_2.rb फ़ाइल इच्छा उत्पादन मैं CAN Cheezburger गया है:

कुछ शोध करने के बाद मैं एक उदाहरण है कि एक जवाब हो सकता है पाया। अगर मैं यह अच्छी तरह समझ गया - पहली चीज जो होती है वह यह है कि बेस क्लास बार मॉड्यूल को शामिल करने का प्रयास करता है। इस समावेशन के समय self.included विधि लागू की गई है, जो बार मॉड्यूल के साथ बार मॉड्यूल (और इसके उदाहरण has_one विधि) को बढ़ाता है। तो सार has_one विधि में बेस क्लास में विधि (मिश्रित?) शामिल है। लेकिन फिर भी, मैं इसे पूरी तरह से प्राप्त नहीं करता हूं। Object#extend मॉड्यूल से विधि जोड़ता है लेकिन फिर भी, मुझे यकीन नहीं है कि विस्तार का उपयोग करके इस व्यवहार को पुन: उत्पन्न कैसे करें। तो मेरे प्रश्न हैं:

  1. वास्तव में यहां क्या हुआ। मेरा मतलब है, अभी भी नहीं पता कि has_one विधि क्लास विधि कैसे बनती है? किस भाग ने वास्तव में इसका कारण बनाया?

  2. इस विधि कॉल (जो कॉन्फ़िगरेशन की तरह दिखता है) बनाने की संभावना वास्तव में अच्छी है। क्या यह हासिल करने का कोई वैकल्पिक या आसान तरीका है?

उत्तर

9

आप कर सकते हैं extend और include एक मॉड्यूल।

module Bar 
    def has_one stuff 
    puts "I CAN HAS #{stuff}?" 
    end 
end 

class Model 
    extend Bar 
    has_one 'CHEEZBURGER' 
end 

include उदाहरण तरीके के रूप में मॉड्यूल से तरीकों

class Model 
    include Bar 
end 
Model.new.has_one 'CHEEZBURGER' 

रेल को यह का उपयोग करता है कहते हैं:

extend वर्ग तरीकों अपने उदाहरण के एक सरल कार्यान्वयन के रूप में मॉड्यूल से तरीकों कहते हैं गतिशील रूप से अपनी कक्षा में विधियों को जोड़ें।

उदाहरण के लिए आप define_method इस्तेमाल कर सकते हैं:

module Bar 
    def has_one stuff 
    define_method(stuff) do 
     puts "I CAN HAS #{stuff}?" 
    end 
    end 
end 

class Model 
    extend Bar 
    has_one 'CHEEZBURGER' 
end 

Model.new.CHEEZBURGER # => I CAN HAS CHEEZBURGER? 
3

मैं जादू में विश्वास करने के इनकार करने के लिए आप हूं। I अत्यधिक आपको Metaprogramming Ruby पुस्तक प्राप्त करने की सलाह देते हैं।मुझे हाल ही में यह मिला है और यह महा ब्रेनज़ में बाएं और दाएं epiphanies ट्रिगर था। यह इन चीजों में से कई पर जाता है जिन्हें आम तौर पर लोग 'जादू' के रूप में संदर्भित करते हैं। एक बार यह उन सभी को कवर करने के बाद, यह आपको दिखाने के लिए एक उदाहरण के रूप में सक्रिय रिकॉर्ड पर चला जाता है कि अब आप विषयों को समझते हैं। सबसे अच्छा, पुस्तक बहुत आसानी से पढ़ती है: यह बहुत पचाने योग्य और छोटा है।

0

इसके अलावा, आप एक (आमतौर पर भारी दुरुपयोग, लेकिन कभी कभी बहुत उपयोगी) method_missing अवधारणा का उपयोग कर सकते हैं:

class Foo 
    def method_missing(method, *arg) 
     # Here you are if was some method that wasn't defined before called to an object 
     puts "method = #{method.inspect}" 
     puts "args = #{arg.inspect}" 
     return nil 
    end 
end 

Foo.new.abracadabra(1, 2, 'a') 

पैदावार

method = :abracadabra 
args = [1, 2, "a"]

आम तौर पर, इस तंत्र अक्सर

के रूप में प्रयोग किया जाता है
def method_missing(method, *arg) 
    case method 
    when :has_one 
    # implement has_one method 
    when :has_many 
    # ... 
    else 
    raise NoMethodError.new 
    end 
end 
संबंधित मुद्दे