2011-05-01 13 views
28

में एक ब्लॉक के अंदर बाध्यकारी/संदर्भ बदले मैं रूबी में एक डीएसएल कि इतने की तरह काम करता है:माणिक

desc 'list all todos' 
command :list do |c| 
    c.desc 'show todos in long form' 
    c.switch :l 
    c.action do |global,option,args| 
    # some code that's not relevant to this question 
    end 
end 

desc 'make a new todo' 
command :new do |c| 
    # etc. 
end 

एक साथी डेवलपर मैं अपने डीएसएल बढ़ाने command ब्लॉक करने के लिए c गुजर की आवश्यकता नहीं करने का सुझाव दिया है, और इस प्रकार सभी के अंदर विधियों के लिए c. की आवश्यकता नहीं है; शायद, वह मैं निम्नलिखित कोड काम ही कर सकता है निहित:

desc 'list all todos' 
command :list do 
    desc 'show todos in long form' 
    switch :l 
    action do |global,option,args| 
    # some code that's not relevant to this question 
    end 
end 

desc 'make a new todo' 
command :new do 
    # etc. 
end 

command के लिए कोड लग रहा है कुछ

तरह
def command(*names) 
    command = make_command_object(..) 
    yield command                              
end 

मैं कई बातें करने की कोशिश की और यह काम करने के लिए प्राप्त करने में असमर्थ था, मैं command ब्लॉक के अंदर कोड के संदर्भ/बाध्यकारी को डिफ़ॉल्ट से अलग करने के तरीके को समझ नहीं पाया।

यदि यह संभव है तो कोई विचार और मैं इसे कैसे कर सकता हूं?

उत्तर

27

यह कोड पेस्ट करें:

def evaluate(&block) 
    @self_before_instance_eval = eval "self", block.binding 
    instance_eval &block 
    end 

    def method_missing(method, *args, &block) 
    @self_before_instance_eval.send method, *args, &block 
    end 

अधिक जानकारी के लिए यह वास्तव में अच्छा लेख का संदर्भ लें here

+0

विशेष का मूल्यांकन है: यहाँ एक और सवाल से लिखने हो रहा है? लिंक्ड आलेख इसे इस तरह इंगित नहीं करता है। मेरा कोड, 'कमांड' की परिभाषा में, 'उपज' करता है। क्या आप कह रहे हैं कि मुझे अपने विधि सिग में ब्लॉक करना चाहिए, और फिर example_eval जो उपज के बजाय ब्लॉक करता है? (इस जानकारी के साथ प्रश्न अद्यतन) – davetron5000

4
class CommandDSL 
    def self.call(&blk) 
    # Create a new CommandDSL instance, and instance_eval the block to it 
    instance = new 
    instance.instance_eval(&blk) 
    # Now return all of the set instance variables as a Hash 
    instance.instance_variables.inject({}) { |result_hash, instance_variable| 
     result_hash[instance_variable] = instance.instance_variable_get(instance_variable) 
     result_hash # Gotta have the block return the result_hash 
    } 
    end 

    def desc(str); @desc = str; end 
    def switch(sym); @switch = sym; end 
    def action(&blk); @action = blk; end 
end 

def command(name, &blk) 
    values_set_within_dsl = CommandDSL.call(&blk) 

    # INSERT CODE HERE 
    p name 
    p values_set_within_dsl 
end 

command :list do 
    desc 'show todos in long form' 
    switch :l 
    action do |global,option,args| 
    # some code that's not relevant to this question 
    end 
end 

प्रिंट होगा:

:list 
{:@desc=>"show todos in long form", :@switch=>:l, :@action=>#<Proc:[email protected]:/Users/Ryguy/Desktop/tesdt.rb:38>} 
9
शायद

def command(*names, &blk) 
    command = make_command_object(..) 
    command.instance_eval(&blk) 
end 

कमांड ऑब्जेक्ट के संदर्भ में ब्लॉक का मूल्यांकन कर सकते हैं।

2

मैंने एक ऐसी कक्षा लिखी जो इस सटीक मुद्दे को संभालती है, और @instance_variable पहुंच, घोंसले और इसी तरह की चीजों से संबंधित है।

Block call in Ruby on Rails