2010-06-22 8 views
17

मैं रूबी के लिए नया हूं, और अब तक, यह पता लगाने के लिए कि "binding" objects का उपयोग कैसे करें मेरे लिए सबसे बड़ा दर्द बिंदु है। अगर मैं सही ढंग से दस्तावेज़ीकरण पढ़ रहा हूं, तो वे लगभग पूरी तरह से अपारदर्शी हैं। बाइंडिंग ऑब्जेक्ट के अंदर दायरे तक पहुंचने के लिए, आपको बाध्यकारी का उपयोग करके रूबी कोड और eval की स्ट्रिंग रखना होगा।रूबी में बाइंडिंग ऑब्जेक्ट्स के साथ बातचीत करने का एकमात्र तरीका 'eval' है?

शायद मैं सिर्फ एक अलग स्कूल से एक शुद्धवादी हूं, लेकिन मैं आम तौर पर बोलने वाली स्ट्रिंग-आधारित 'eval' संरचनाओं के लिए एलर्जी हूं। वहाँ निम्नलिखित, सुरक्षित रूप से और सामान्य स्थिति में से कोई भी कार्य करने के लिए किसी भी तरह से, एक बाध्यकारी वस्तु दिया जाता है:

  1. सूची संदर्भ में दायरे में पहचानकर्ता बंधन का प्रतिनिधित्व करता है, या सामग्री की एक हैश पुनः प्राप्त।
  2. बाहरी संदर्भ में कुछ स्थानीय चर के बराबर बाध्यकारी में स्थानीय चर का मान सेट करें। आदर्श रूप में, यह आम तौर पर काम करना चाहिए, भले ही मान एक ऑब्जेक्ट संदर्भ, फ़ाइल हैंडल, या कुछ अन्य जटिल इकाई है।
  3. (एक्सटेंशन 2 :) एक हैश को देखते हुए, प्रत्येक प्रविष्टि के लिए बाध्यकारी में स्थानीय सेट करें।
  4. अभी तक बेहतर है, हैश को के साथ बाध्यकारी बनाने के लिए केवल मूल भाषा संरचनाएं और हैश में नाम हैं।

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

वैकल्पिक रूप से, क्या कोड को निकालने का कोई तरीका है जिसे पहले से ही बाध्यकारी के संदर्भ में पार्स किया गया है, पर्ल के eval ब्लॉक सिंटैक्स के समान? http://wikis.onestepback.org/index.cgi/Tech/Ruby/RubyBindings.rdoc/style/print

बाकी जिम Shubert के सहायक संकेत के बाद प्रयोग से है:

के आधार पर:

+1

इस प्रश्न को और अधिक @ Jörg W Mittag की आवश्यकता है: पी –

उत्तर

7

अधिक खोज पर, मैं अपने प्रश्न के कम से कम हिस्सा का जवाब मिल गया।

  1. यह eval आईएनजी local_variables, instance_variables और global_variables बाध्यकारी अंदर के द्वारा पूरा किया जा सकता है।
  2. आप नीचे वर्णित कुछ कर सकते हैं, var_name, new_val, my_binding (वाक्यविन्यास अपूर्ण या अयोग्य हो सकता है, टिप्पणियों में सुझाव देने के लिए स्वतंत्र महसूस करें। इसके अलावा, मुझे सूची के अंदर काम करने के लिए कोड स्वरूपण नहीं मिल सका, सुझाव यह कैसे किया जाएगा इसे भी लागू किया जाएगा।)
  3. आप सीधे (2) ले सकते हैं और हैश को ऐसा करने के लिए लूप कर सकते हैं।
  4. नीचे दूसरा कोड ब्लॉक देखें। विचार TOPLEVEL_BINDING से शुरू करना है, जो मुझे विश्वास है कि आम तौर पर वैश्विक चर शामिल हैं।

इसमें स्ट्रिंग eval का उपयोग शामिल है। हालांकि, किसी भी वैरिएबल वैल्यू को कभी भी स्ट्रिंग्स में शामिल नहीं किया जाता है, इसलिए वर्णित रूप में उपयोग किए जाने पर इसे काफी सुरक्षित होना चाहिए, और जटिल चर मूल्यों में 'पास' करने के लिए काम करना चाहिए।

यह भी ध्यान रखें कि एक चर के मूल्य प्राप्त करने के लिए eval var_name, my_binding करना हमेशा संभव है।ध्यान दें कि इन सभी उपयोगों में यह महत्वपूर्ण है कि चर के नाम eval करने के लिए सुरक्षित रहें, इसलिए यह आदर्श रूप से किसी भी प्रकार के उपयोगकर्ता इनपुट से नहीं आना चाहिए।

अंदर एक बाध्यकारी var_name दिया, new_val एक चर, my_binding स्थापना:

# the assignment to nil in the eval coerces the variable into existence at the outer scope 
setter = eval "#{var_name} = nil; lambda { |v| #{var_name} = v }", my_binding 
setter.call(new_val) 

बिल्डिंग एक "bespoke" बाइंडिंग:

my_binding = eval "lambda { binding }", TOPLEVEL_BINDING # build a nearly-empty binding 
# set_in_binding is based on the above snippet 
vars_to_include.each { |var_name, new_val| set_in_binding(var_name, new_val, my_binding) } 
+1

उत्कृष्ट शोध! –

+3

इसे स्वीकार करते हुए, लेकिन अगर कोई इस बात के लिए आता है कि इस सामान के लिए स्ट्रिंग eval के उपयोग से कैसे बचें, तो कृपया अपना ज्ञान योगदान दें। –

3

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

[email protected]:~> irb 
irb(main):001:0> eval "self", TOPLEVEL_BINDING 
=> main 
irb(main):002:0> eval "instance_variables", TOPLEVEL_BINDING 
=> [] 
irb(main):003:0> eval "methods", TOPLEVEL_BINDING 
=> ["irb_kill", "inspect", "chws", "install_alias_method", .... 

मैं भी Metaprogramming रूबी जो बंधन के बारे में बहुत बात नहीं करता है। हालांकि, अगर आप इस पेज के अंत में लेने, 144 यह कहता है

एक मायने में, आप बंद ब्लॉक से एक "शुद्ध" फार्म के रूप में वस्तुओं बाइंडिंग देख सकते हैं, क्योंकि इन वस्तुओं एक होते हैं दायरा लेकिन कोड नहीं है।

और, विपरीत पृष्ठ पर, यह आईआरबी के कोड को संवारता (eval कॉल करने के लिए पिछले दो आर्ग को हटाने) यह कैसे बाइंडिंग का उपयोग करता है देखने के लिए पता चलता है:

// ctwc/आईआरबी/workspace.rb
eval (बयान, @binding) #, फ़ाइल, लाइन)

और ... मैं लैम्ब्डा गुजर सुझाव देने के लिए जा रहा था, लेकिन मैं देख रहा हूँ कि आप सिर्फ इतना है कि उत्तर दिया, तो मैं एक के रूप में आईआरबी फेरबदल छोड़ देंगे आगे के शोध के लिए सुझाव।

+0

धन्यवाद, 'instance_variables' निर्माण मेरे लिए नया है, जो मुझे कुछ और कूदने वाले अंक देता है। आईआरबी की जांच करने के लिए निर्देश भी सहायक है। मैंने इसे ऊपर उठाया है लेकिन इसे स्वीकार नहीं किया है, क्योंकि यह सीधे पूछे गए प्रश्नों का उत्तर नहीं देता है। –

+0

वाल्टर, धन्यवाद। मुझे उम्मीद है कि कम से कम आपको काम करने और जवाब खोजने के लिए कुछ विचार दिए गए हैं। मुझे यकीन है कि आपने जो पूछा है वह संभव है, क्योंकि आईबीबी सीधे बाइंडिंग के साथ काम करता है (आईआरबी खुद में एक रूबी क्लास है)। –

1

क्या आप समझा सकते हैं कि आप वास्तव में क्या करने की कोशिश कर रहे हैं? कृपया कुछ कोड प्रदान करें जो दिखाते हैं कि आप इसे कैसे काम करना चाहते हैं। आप जो चाहते हैं उसे पूरा करने के लिए एक बेहतर और सुरक्षित तरीका हो सकता है।

मैं आपके सामान्य उपयोग-मामले का अनुमान लगाने के लिए एक शॉट लेने जा रहा हूं। एक हैश को देखते हुए: {: एक => 11,: ख => 22}

आप एक न्यूनतम, अपेक्षाकृत-पृथक निष्पादन वातावरण जहां आप स्थानीय-चर के रूप में हैश के मूल्यों का उपयोग कर सकते हैं। (मुझे बिल्कुल यकीन नहीं है कि आपको स्थानीय लोगों के लिए क्यों आवश्यकता होगी, सिवाय इसके कि यदि आप एक डीएसएल लिख रहे हैं, या यदि आपके पास पहले ही लिखित कोड है जिसे आप हैश तक पहुंचने के लिए अनुकूलित नहीं करना चाहते हैं।)

मेरा प्रयास यहां है। सादगी के लिए, मुझे लगता है कि आप केवल हैश कुंजी के रूप में प्रतीकों का उपयोग करते हैं।

 
class MyBinding 
    def initialize(varhash); @vars=varhash; end 
    def method_missing(methname, *args) 
    meth_s = methname.to_s 
    if meth_s =~ /=\z/ 
     @vars[meth_s.sub(/=\z/, '').to_sym] = args.first 
    else 
     @vars[methname] 
    end 
    end 
    def eval(&block) 
    instance_eval &block 
    end 
end 

नमूना उपयोग:

 
hash = {:a => 11, :b => 22} 
mb = MyBinding.new hash 
puts mb.eval { a + b } 
# setting values is not as natural: 
mb.eval { self.a = 33 } 
puts mb.eval { a + b } 

कुछ चेतावनियां:

1) यदि चर मौजूद नहीं था मैं एक NameError बढ़ा नहीं था, लेकिन एक सरल प्रतिस्थापन ठीक करता है कि:

 
def initialize(varhash) 
    @vars = Hash.new {|h,k| raise NameError, "undefined local variable or method `#{k}'" } 
    @vars.update(varhash) 
end 

2) सामान्य स्कोपिंग नियम ऐसे हैं कि यदि कोई स्थानीय मौजूद है जिसका नाम विधि के समान है, तो स्थानीय पी प्रतिधारण, जब तक कि आप स्पष्ट रूप से एक विधि कॉल नहीं करते हैं, जैसे कि()।उपरोक्त वर्ग में विपरीत व्यवहार है; विधि प्राथमिकता लेता है। "सामान्य" व्यवहार प्राप्त करने के लिए, आपको #object_id जैसे मानक विधियों के सभी (या अधिकतर) को छिपाने की आवश्यकता होगी। ActiveSupport इस उद्देश्य के लिए एक ब्लैंकस्लेट श्रेणी प्रदान करता है; यह केवल 3 विधियों को रखता है:

 __send__, instance_eval, __id__

। इसका उपयोग करने के लिए, केवल ब्लैकस्लेट से MyBinding उत्तराधिकारी बनाएं। इन 3 विधियों के अलावा, आप "eval" या "method_missing" नामक स्थानीय भी नहीं पाएंगे।

3) स्थानीय सेट करना स्वाभाविक नहीं है, क्योंकि इसे विधि कॉल प्राप्त करने के लिए "स्वयं" की आवश्यकता होती है। सुनिश्चित नहीं है कि इसके लिए कोई समाधान है या नहीं।

4) eval ब्लॉक @vars हैश के साथ गड़बड़ कर सकता है।

5) यदि आपके पास उस क्षेत्र में वास्तविक स्थानीय var है जहां आप mb.eval को कॉल करते हैं, उसी नाम के साथ हैश कुंजी में से एक के रूप में, असली स्थानीय प्राथमिकता लेगा ... यह शायद सबसे बड़ा नकारात्मक कारण है क्योंकि सूक्ष्म बग में रेंग सकते हैं।

मेरी तकनीक के लिए डाउनसाइड्स को महसूस करने के बाद, मैं चर के सेट को रखने के लिए सीधे हैश का उपयोग करने की सिफारिश कर रहा हूं, जब तक कि मुझे कोई कारण न दिखाई दे। लेकिन यदि आप अभी भी देशी eval का उपयोग करना चाहते हैं, तो आप कोड इंजेक्शन से बचने के लिए Regexps का उपयोग करके सुरक्षा में सुधार कर सकते हैं, और "स्थानीय रूप से" प्रोफ़ का उपयोग करके eval कॉल के लिए $ SAFE को उच्च स्थान पर सेट कर सकते हैं, जैसे:

 
proc { $SAFE = 1; eval "do_some_stuff" }.call # returns the value of eval call 
0

यहां हैश-आधारित समाधान के लिए कुछ कोड है।

 
class ScopedHash 
    def initialize(varhash) 
    # You can use an OpenStruct instead of a Hash, but the you lose the NameError feature. 
    # OpenStructs also don't have the ability to list their members unless you call a protected method 
    @vars = Hash.new {|h,k| raise NameError, "undefined local variable or method `#{k}'" } 
    @vars.update(varhash) 
    end 
    def eval 
    yield @vars 
    end 
end 

if __FILE__ == $0 
    # sample usage 
    hash = {:a => 11, :b => 22} 
    sh = ScopedHash.new hash 
    puts sh.eval {|v| v[:a] + v[:b] } 
    sh.eval {|v| v[:a] = 33 } 
    puts sh.eval {|v| v[:a] + v[:b] } 
    sh.eval{|v| v[:c] } # raises NameError 
end 

तो, स्थानीय लोगों का उपयोग करने के स्थान पर, आप केवल उपज वाले हैश तक पहुंच पाएंगे। मुझे लगता है कि बहुत कम कारण हैं जहां किसी को बाइंडिंग ऑब्जेक्ट में हेरफेर करने के लिए मजबूर किया जाएगा; कार्य को पूरा करने के लिए आमतौर पर क्लीनर तरीके होते हैं।

+0

बाइंडिंग में हेरफेर करने की सलाह के बावजूद, यह इस प्रश्न का विषय था। यह सुझाव पूछा गया सवाल का जवाब नहीं देता है। -1 –

+0

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

+0

प्रश्न बाद के अधिक है। मुझे लगता है कि टेम्पलेट्स के साथ प्रयोग करते समय मैं इसके साथ आया, लेकिन यह पूछने का मेरा वास्तविक कारण यह जानना था कि भाषा बाध्यकारी वस्तुओं को आत्मनिर्भर करने में कितनी अच्छी तरह से काम करती है। हाँ, वह था - मैं टेम्पलेट आमंत्रण के लिए एक नियंत्रित नामस्थान बनाना चाहता था, केवल एक विशेष हैश सेट से मूल्यों के साथ, टेम्पलेट को लिखे गए तरीके को बदलने के बिना, ताकि वह हैश से गुजर सके। –

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