2009-05-02 7 views
47

रेल बुक पर रूबी में कोड के इस टुकड़े को देखा। यह पहला दृश्य है और दूसरा एक सहायक मॉड्यूल है। मुझे समझ में नहीं आता कि &block और attributes={} चीज काम कैसे करता है। क्या कोई मुझे इस तरह समझाते हुए किसी ट्यूटोरियल में मार्गदर्शन कर सकता है?रूबी में यह क्या है और अवरुद्ध है? और यह एक विधि में कैसे पारित किया जाता है?

<% hidden_div_if(@cart.items.empty?, :id => "cart") do %> 
<%= render(:partial => "cart", :object => @cart) %> 
<% end %> 

module StoreHelper 
def hidden_div_if(condition, attributes = {}, &block) 
    if condition 
    attributes["style"] = "display: none" 
    end 
    content_tag("div", attributes, &block) 
    end 
end 

उत्तर

78

ब्लॉक रूबी का एक काफी मूल हिस्सा हैं। वे do |arg0,arg1| ... end या { |arg0,arg1,arg2| ... } द्वारा सीमित हैं।

वे आपको किसी विधि को पास करने के लिए कॉलबैक निर्दिष्ट करने की अनुमति देते हैं। इसके लिए कॉलबैक दो तरीके लागू किया जा सकता है - या तो एक अंतिम तर्क & उपसर्ग के साथ निर्दिष्ट द्वारा पर कब्जा यह द्वारा, या द्वारा yield कीवर्ड का उपयोग:

irb> def meth_captures(arg, &block) 
     block.call(arg, 0) + block.call(arg.reverse , 1) 
    end 
#=> nil 
irb> meth_captures('pony') do |word, num| 
     puts "in callback! word = #{word.inspect}, num = #{num.inspect}" 
     word + num.to_s 
    end 
in callback! word = "pony" num = 0 
in callback! word = "ynop" num = 1 
#=> "pony0ynop1" 
irb> def meth_yields(arg) 
     yield(arg, 0) + yield(arg.upcase, 1) 
    end 
#=> nil 
irb> meth_yields('frog') do |word, num| 
     puts "in callback! word = #{word.inspect}, num = #{num.inspect}" 
     word + num.to_s 
    end 
in callback! word = "frog", num = 0 
in callback! word = "FROG", num = 1 
#=> "frog0FROG1" 

ध्यान दें कि हमारे कॉलबैक प्रत्येक मामले में एक ही था - हम किसी ऑब्जेक्ट में हमारी कॉलबैक सहेजकर दोहराव को हटा सकता है, और उसके बाद प्रत्येक विधि को पास कर सकता है। यह किसी ऑब्जेक्ट में कॉलबैक कैप्चर करने के लिए lambda का उपयोग करके किया जा सकता है, और उसके बाद & के साथ इसे उपसर्ग करके एक विधि में पास किया गया।

irb> callback = lambda do |word, num| 
     puts "in callback! word = #{word.inspect}, num = #{num.inspect}" 
     word + num.to_s 
    end 
#=> #<Proc:[email protected](irb):22> 
irb> meth_captures('unicorn', &callback) 
in callback! word = "unicorn", num = 0 
in callback! word = "nrocinu", num = 1 
#=> "unicorn0nrocinu1" 
irb> meth_yields('plate', &callback) 
in callback! word = "plate", num = 0 
in callback! word = "PLATE", num = 1 
#=> "plate0PLATE1" 

यह यहाँ एक समारोह

    एक समारोह परिभाषा
  • के अंतिम तर्क करने के लिए एक उपसर्ग के रूप में & के विभिन्न उपयोगों समझना महत्वपूर्ण है, यह उस वस्तु में किसी भी पारित कर दिया ब्लॉक कब्जा
  • में एक फंक्शन कॉल, यह ब्लॉक

में दिए गए कॉलबैक ऑब्जेक्ट को विस्तारित करता है यदि आप आसपास के ब्लॉक को देखते हैं तो विशेष रूप से पूरे स्थान पर उपयोग किया जाता है, खासकर इटरेटर में, Array#each की तरह।

+0

इसके लिए धन्यवाद, वास्तव में मेरे लिए सहायक! – duykhoa

+0

धन्यवाद आदमी - बहुत अच्छा उदाहरण है, लेकिन फिक्सम पर निरीक्षण करने का क्या मतलब है? – sekmo

10

&block रूबी कोड का एक टुकड़ा में एक विधि है कि विधि के दायरे में है कि कोड भेजने में और उसके बाद मूल्यांकन का एक तरीका है। आपके उदाहरण कोड में इसका मतलब है कि एक आंशिक नामित कार्ट एक div में प्रस्तुत किया जाएगा। मुझे लगता है कि कंप्यूटर विज्ञान में closure शब्द का उपयोग किया जाता है।

तो अपने उदाहरण में &block है:

<%= render(:partial => "cart", :object => @cart) %> 

कुछ अच्छा पढ़ने और ब्लॉक, procs और lamdas का एक विवरण Robert Sosinski's blog में पाया जा सकता।

+1

हाँ, रुबी में ब्लॉक केवल बंद हैं। इसके बारे में अच्छी व्याख्या के लिए, http://reprog.wordpress.com/2010/02/27/closures-finally-explained/ देखें। –

4

पुन attributes = {}, यह डिफ़ॉल्ट मान के साथ एक विधि तर्क है। तो यदि आप hidden_div_if(whatever) पर कॉल करते हैं, यानी, केवल पहला तर्क गुजर रहा है, attributes एक खाली हैश के लिए डिफ़ॉल्ट होगा।

यह उपयोगी है क्योंकि यह attributes["style"] को बाद में सेट करने में आसान बनाता है, क्योंकि attributes को पहले हैश में प्रारंभ करने की आवश्यकता नहीं है। (जो फिर भी (attributes ||= {})["style"] = … के रूप में बस से किया जा सकता है।)


&block केवल थोड़ा अधिक जटिल है।

रूबी विधियां विशेष वाक्यविन्यास method(args) { |block_args| block_code } का उपयोग करके एक अंतिम तर्क ले सकती हैं जो एक ब्लॉक है। &block मूल रूप से उस ब्लॉक को block चर में Proc ऑब्जेक्ट के रूप में कैप्चर करता है। तो block यहां एक अज्ञात प्रक्रिया को इंगित करने वाला एक चर है।

जब बाद में content_tag कहा जाता है, और &block अपने पिछले तर्क के रूप में पारित हो जाता है, यह एक ब्लॉक में विस्तार किया है कॉल की तरह करता है, तो वास्तव में content_tag(…) { block originally passed to hidden_if_div }


था तो शायद मैं वास्तव में यहाँ भ्रामक था। आपको "रूबी डिफॉल्ट तर्क" और "रूबी ब्लॉक" के लिए क्या करना चाहिए।

1

यह इस तरह काम करता है:

@cart.items.empty? codition

:id => "cart" हो जाता है प्रति सम्मेलन के रूप में विशेषताओं अगर यह पिछले एक है आप एक परम हैश पर {} को दूर कर सकते हैं।

ब्लॉक

render(:partial => "cart", :object => @cart)

समारोह के भीतर

इतना है अगर कार्ट खाली है इसके साथ मूल्य विशेषता शैली जोड़ना होगा "प्रदर्शन: कोई"

तो यह एक div टैग बनाएगा ब्लॉक को निष्पादित करने के परिणाम की सामग्री से भरा जो @cart की सामग्री के साथ आंशिक दृश्य कार्ट को प्रस्तुत करने का परिणाम होगा।

3

रूबी ब्लॉक्स, प्रोसेस और लैम्बडा लागू करता है जिन्हें कंप्यूटर विज्ञान समुदाय में बंद करने के रूप में जाना जाता है। यदि आप रूबी सीखना शुरू करते हैं तो आप इस तरह दिखने वाले कोड में जल्दी से भाग लेंगे।

a = ["dog", "cat", "bird"] 
a.alter_each! do |n, i| 
    "#{i}_#{n}" 
end 

तो यहां क्या चल रहा है?

हम जानवरों के नामों की एक श्रृंखला के साथ शुरू करते हैं और alter_each कहते हैं! एक ब्लॉक गुजरने की विधि। कोड के इस ब्लॉक में हम निर्दिष्ट कर सकते हैं कि हम प्रत्येक आइटम को कैसे बदलना चाहते हैं। हमारा उदाहरण प्रत्येक पशु नाम को सरणी में इसकी स्थिति के साथ उपसर्ग करेगा। Alter_each के रूप में! विधि प्रत्येक आइटम के माध्यम से पुनरावृत्त करती है जो हमारे ब्लॉक को मूल्य और अनुक्रमणिका से गुज़रने के लिए निष्पादित करेगी। हमारा ब्लॉक इन पैराम को कैप्चर करता है, इंडेक्स को नाम से उपसर्ग करता है और परिणाम देता है। अब आइटर_च को देखें! तरीका।

ध्यान दें कि विधि किसी भी पैराम निर्दिष्ट नहीं करती है, ऐसा इसलिए है क्योंकि एक ब्लॉक स्वचालित रूप से उपज कीवर्ड के लिए असाइन किया जाता है। उपज को सरणी में प्रत्येक आइटम के मूल्य और अनुक्रमणिका में गुजरने वाले फ़ंक्शन की तरह कहा जाता है और मूल मान को ओवरराइड किया जाता है।

class Array 
    def alter_each! 
    self.each_with_index do |n, i| 
     self[i] = yield(n,i) 
    end 
    end 
end 

क्या होगा यदि आपको इस विधि में परम पारित करने की आवश्यकता है?

आप पैरा को स्वीकार करने के लिए विधि हस्ताक्षर को संशोधित कर सकते हैं और आखिर में एक एम्परसैंड से शुरू होने वाले परम के साथ ब्लॉक को पकड़ सकते हैं। नीचे दिए गए उदाहरण में हमारे ब्लॉक को & ब्लॉक पैरामीटर के साथ कैप्चर किया जाएगा जिसे हम कॉल विधि का आह्वान करेंगे।यह उपज

class Array 
    def modify_each!(add_one = true, &block) 
    self.each_with_index do |n, i| 
     j = (add_one) ? (i + 1) : i 
     self[i] = block.call(n,j) 
    end 
    end 
end 
का उपयोग कर के स्थान पर है

Full article on ruby blocks

18

ब्लाकों, Procs और lambdas (कंप्यूटर विज्ञान में बंद के रूप में) रूबी के सबसे शक्तिशाली पहलुओं में से एक है, और भी सबसे गलत समझा में से एक हैं । ऐसा शायद इसलिए है क्योंकि रूबी एक अद्वितीय तरीके से बंद हो जाती है। चीजों को और अधिक जटिल बनाना यह है कि रुबी के पास बंद करने का उपयोग करने के चार अलग-अलग तरीके हैं, जिनमें से प्रत्येक एक अलग है, और कभी-कभी बकवास होता है। रूबी के भीतर बंद होने के तरीके के बारे में कुछ अच्छी जानकारी के साथ बहुत सी साइटें हैं। लेकिन मुझे अभी तक एक अच्छी, निश्चित मार्गदर्शिका नहीं मिली है।

class Array 
    def iterate!(&code) 
    self.each_with_index do |n, i| 
     self[i] = code.call(n) 
    end 
    end 
end 

array = [1, 2, 3, 4] 

array.iterate! do |n| 
    n ** 2 
end 

प्रक्रिया, उर्फ, Procs

ब्लाकों, बहुत आसान और वाक्य रचना आसान है लेकिन हम अपने निपटान में कई अलग अलग ब्लॉक हैं और उन्हें कई बार उपयोग कर सकते हैं। इस प्रकार, एक ही ब्लॉक को बार-बार गुजरने के लिए हमें खुद को दोहराने की आवश्यकता होगी। हालांकि, चूंकि रूबी पूरी तरह से ऑब्जेक्ट उन्मुख है, इसे ऑब्जेक्ट के रूप में पुन: प्रयोज्य कोड को सहेजकर इसे साफ़ रूप से संभाला जा सकता है। इस पुन: प्रयोज्य कोड को प्रो (प्रक्रिया के लिए छोटा) कहा जाता है। ब्लॉक और प्रोसेस के बीच एकमात्र अंतर यह है कि एक ब्लॉक एक प्रक्रिया है जिसे सहेजा नहीं जा सकता है, और इस तरह, एक बार उपयोग समाधान है। दो तरह से

class Array 
    def iterate!(code) 
    self.each_with_index do |n, i| 
     self[i] = code.call(n) 
    end 
    end 
end 

array_1 = [1, 2, 3, 4] 
array_2 = [2, 3, 4, 5] 

square = Proc.new do |n| 
    n ** 2 
end 

lambdas

अब तक, आप का इस्तेमाल किया है Procs, उन्हें एक विशेषता के रूप में सीधे गुजर और उन्हें एक चर के रूप में बचत: Procs साथ काम करके, हम आपको निम्न कार्य शुरू कर सकते हैं। ये प्रक्रियाएं अन्य भाषाओं के समान काम करती हैं जो अज्ञात कार्यों या भेड़ के बच्चे हैं। चीजों को और अधिक रोचक बनाने के लिए, रूबी भी रूबी के भीतर उपलब्ध हैं। एक नज़र डालें: जिस तरह से रूबी में बंद का उपयोग करने "की तरह रूबी"

class Array 
    def iterate!(code) 
    self.each_with_index do |n, i| 
     self[i] = code.call(n) 
    end 
    end 
end 

array = [1, 2, 3, 4] 

array.iterate!(lambda { |n| n ** 2 }) 

puts array.inspect 

ब्लाकों

सबसे आम, सबसे आसान और यकीनन सबसे ब्लॉकों के साथ है। उनके पास निम्नलिखित परिचित वाक्यविन्यास हैं:

array = [1, 2, 3, 4] 

array.collect! do |n| 
    n ** 2 
end 

puts array.inspect 

# => [1, 4, 9, 16] 
+0

मैंने यहां एक समान उदाहरण देखा है http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ हालांकि मैं उलझन में हूं कि '| n, i | 'क्या यह सरणी के भीतर मान और सूचकांक स्थान है? – Tom

+0

ठीक है मैं मूर्खतापूर्ण था प्रत्येक_with_index एक विधि है: 'प्रत्येक_with_index | आइटम, अनुक्रमणिका | 'तो मुझे वास्तव में सवाल पूछने की आवश्यकता नहीं थी। – Tom

+1

जब आपने इस जवाब को रॉबर्सोसिंकी की साइट से कॉपी किया था, तो आप उन दोनों पंक्तियों को शामिल करना भूल गए थे जो 'सरणी' दोनों सरणी को पार करते हैं - जब तक मैं अपना मूल संस्करण पढ़ता हूं तब तक थोड़ा उलझन में था। शायद अगली बार अपने स्रोत को इंगित करें। – moosefetcher

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