2010-03-24 22 views
3

我想補充一些(1)調試爲我簡單的Ruby的功能,我下面寫了一個函數,把一個變量name = value的格式在Ruby中

def debug(&block) 
    varname = block.call.to_s 
    puts "#{varname} = #{eval(varname,block)}" 
end 

debug {:x} #prints x = 5 
debug {:y} #prints y = 5 

我明白的eval是邪惡的。所以我有兩個問題。

  1. 有什麼方法可以在不使用eval的情況下編寫調試方法嗎?如果NO是否有這樣做的首選方法?
  2. 有沒有辦法將參數列表傳遞給此方法?我理想情況下更喜歡debug {:x,:y。 :anynumOfvariables}。我無法弄清楚如何將它分解到調試方法中(即獲取參數列表)

回答

10

只需使用數組。您可以使用Array方法,以確保你將永遠有一個數組,即使有人經過在只有一個值:

def debug(&block) 
    Array(block[]).each do |var| puts "#{var} = #{eval var.to_s, block}" end 
end 

x, y = 3, 5 

debug {:x} # => "x = 3" 
debug {[:x, :y]} # => "x = 3" "y = 5" 

BTW:傳遞一個塊的結合不再是Ruby 1.9的工作。 (儘管文件稱,確實)。您必須顯式調用Proc#binding來獲取該Proc一個Binding對象:本已經作品的Ruby 1.8

def debug(&block) 
    Array(block.()).flatten.each do |var| 
    puts "#{var} = #{eval var.to_s, block.binding}" 
    end 
end 

幸運的,所以你通過包含它可以保護您的代碼。

另一種方法是完全放棄該塊。我的意思是,你已經強制debug的用戶使用在塊中傳遞參數的不熟悉的習慣用法,而不是在括號中。爲什麼不強迫他們只是通過綁定呢?

def debug(*vars, bnd) 
    vars.each do |var| 
    puts "#{var} = #{eval var.to_s, bnd}" 
    end 
end 

x, y = 3, 5 

debug :x, binding # => "x = 3" 
debug :x, :y, binding # => "x = 3" "y = 5" 

這具有的增加的靈活性,他們實際上可以通過一個不同比一個調用點,例如結合如果他們想要在應用程序的另一部分中實際調試一段代碼的話。


BTW:這裏有一些有趣的Ruby 1.9.2的參數內省(Proc#parameters):

def debug(&block) 
    block.parameters.map(&:last).each do |var| 
    puts "#{var} = #{eval var.to_s, block.binding}" 
    end 
end 

x, y = 3, 5 

debug {|x|} # => "x = 3" 
debug {|x, y|} # => "x = 3" "y = 5" 
+0

@Jörg,很好地完成。你認爲'Array(stuff)'會比'[* stuff] .flatten?更好嗎? – 2010-03-24 16:49:05

+0

@Wayne Conrad:可能。坦率地說,我只是沒有想到它,因爲摔扁平坦的成語是如此深深地燒入我的大腦。如果你傳遞多個參數,'Array()'會中斷,這就是爲什麼我要避免它的原因,但在這種情況下,語言規範保證休息參數將永遠是一個數組。 – 2010-03-24 16:58:04

+0

非常漂亮的寫作,Jörg。這幫助我瞭解了一些讓我困惑很長時間的塊。 +1 – 2010-03-24 18:17:50

0

而且我必須如何使用這些方法從每個循環得到的變量名和值,將它們放置爲嵌套散列的鍵和值?

* attributes數組作爲方法的參數傳遞。 我想遍歷它,並且每個變量的名稱都用作嵌套散列和變量值的鍵值。

我得到這個:

def get_varname(&block) 
    varname = block.call.to_s 
    return varname 
end 

def create_instance_hash(env_attrs_obj, *attributes) 
    if not env_attrs_obj.has_key?("instances") 
     env_attrs_obj["instances"] = "" 
    end 
    attributes.each do |attr| 
     attr_name = get_varname{:attr} 
     env_attrs_obj["instances"][attr_name] = attr 
    end 
end 

instance_nat_ip_pub = "ip_pub_addr" 
instance_nat_ip_prv = "ip_addr" 
instance_nat_ami = "AMI_NAME" 
instance_nat_aws_ssh_key_id = "AWS_SSH_KEY_ID" 
instance_nat_id = "instance_id" 

env_hash = {} 

create_instance_hash(env_hash, *[instance_nat_ip_pub, instance_nat_ip_prv, instance_nat_ami, instance_nat_aws_ssh_key_id, instance_nat_id]) 

但是:

def attrs_each_test(*attributes) 
    attributes.each do |attr| 
     puts get_varname{:attr} 
    end 
end 

,並將其輸出:

attr 
attr 
attr 
attr 
attr 

錯誤when I runcreate_instance_hash

Line 12:in `[]=': string not matched (IndexError) 
    from t.rb:12:in `create_instance_hash' 
    from t.rb:10:in `each' 
    from t.rb:10:in `create_instance_hash' 
    from t.rb:24 

我該如何糾正這個錯誤並實現我的目標?

相關問題