2013-11-20 4 views
5

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

पहुँच प्रतीक तालिका सीधे:: मैं दो दृष्टिकोण है कि तरीकों के सभी मिल पाया

for my $classname (@ARGV) { 
    eval "require $classname"; 
    die "Can't load $classname $EVAL_ERROR" 
     if $EVAL_ERROR; 

    no strict 'refs'; 
    METHODS: 
    for my $sym (keys %{ "${classname}::" }) { 
     next METHODS unless defined &{"${classname}::${sym}"}; 
     print "$sym\n"; 
    } 
} 

CPAN से Class::Inspector मॉड्यूल का उपयोग करें:

for my $classname (@ARGV) { 
    my @methods = Class::Inspector->methods($classname, 'public'); 
    print Dumper \@methods; 
} 

इन दो दृष्टिकोण इसी तरह के परिणाम का निर्माण किया; इनके साथ समस्या यह है कि वे पूरे मॉड्यूल के लिए उपलब्ध विधियों के सभी दिखाते हैं, न कि उस मॉड्यूल के के अंदर परिभाषित विधियों को न केवल।

क्या मॉड्यूल के लिए सुलभ तरीकों और मॉड्यूल के अंदर स्पष्ट रूप से परिभाषित विधियों के बीच अंतर करने का कोई तरीका है?

नोट: मैं अपने उपयोग के मामले में एक पूर्ण कोड कवरेज परीक्षण बनाने का प्रयास नहीं कर रहा हूं, मैं सिर्फ यह जांचना चाहता हूं कि सभी विधियों को कम से कम एक बार बुलाया गया है। Devel::Cover जैसे पूर्ण कवरेज परीक्षण हमारे लिए अधिक हैं।

+0

मैं इस समय इस सत्यापित नहीं कर सकता, लेकिन मैं आप की जरूरत लगता है कि [ 'can'] (http://perldoc.perl.org/perlobj.html#The-UNIVERSAL- कक्षा): 'प्रिंट "$ _ \ n" grep $ classname-> कर सकते हैं ($ _), कुंजी% {"$ {classname} ::}" ' – Zaid

+0

आपकी टिप्पणी के लिए धन्यवाद, दुर्भाग्यवश' अभी भी 'लगता है विरासत के पेड़ को देखो। मुझे अभी भी 'डूपर' और हमारे कुछ कस्टम मॉड्यूल के अन्य तरीकों के लिए प्रविष्टियां मिल रही हैं। –

+0

आप 'स्थानीय @ पैकेज :: NAME :: INC =();' 'कॉल कर सकते हैं और फिर 'can()' चेक कर सकते हैं। – frezik

उत्तर

4

प्रत्येक उप (या अधिक विशेष, प्रत्येक सीवी), याद करते हैं जो पैकेज यह मूल रूप में घोषित किया गया था टेस्ट मामला:।

Foo.pm:

package Foo; 
sub import { 
    *{caller . "::foo"} = sub{}; 
} 
1; 

Bar.pm:

package Bar; 
use Foo; 

our $bar; # introduces *Bar::bar which does not have a CODE slot 
sub baz {} 
1; 

प्रवेश प्रतीक तालिका अब foo और baz दोनों देता है। वैसे, मैं (कारण है कि एक पल में स्पष्ट हो जाएगा के लिए) इस तरह कि कोड लिखने चाहते हैं:

my $classname = 'Bar'; 
for my $glob (values %{ "${classname}::" }) { 
    my $sub = *$glob{CODE} or next; 
    say *$glob{NAME}; 
} 

इसके बाद, हम B module गौर करने underlying C data structure आत्मनिरीक्षण करना होगा। हम इसे B::svref_2object फ़ंक्शन के साथ करते हैं। यह एक B::CV वस्तु जो सुविधाजनक STASH क्षेत्र है (जो एक B::HV वस्तु जो एक NAME क्षेत्र है देता है) का उत्पादन करेगा:

use B(); 
my $classname = 'Bar'; 
for my $glob (values %{ "${classname}::" }) { 
    my $sub = *$glob{CODE} or next; 
    my $cv = B::svref_2object($sub); 
    $cv->STASH->NAME eq $classname or next; 
    say *$glob{NAME}; 
} 

में कुछ विवेक चेकों जोड़ें, और यह बहुत अच्छी तरह से काम करना चाहिए।

गतिशील वर्ग/मॉड्यूल लोडिंग स्ट्रिंग eval के माध्यम से नहीं की जानी चाहिए। इसके बजाय मैं Module::Runtime की सिफारिश:

Module::Runtime::require_module($classname); 
+0

निष्पादित करने के बाद उपयोग कथन के माध्यम से शामिल किया गया है, यह वास्तव में जिस तरह का दृष्टिकोण मैं ढूंढ रहा था, धन्यवाद! 'NAME' की कुछ कॉल 'बी :: विशेष' की वापसी वस्तुएं हैं, यह दस्तावेज़ीकरण से अस्पष्ट है जिसका मतलब है, लेकिन मैं उन्हें केवल उन पर छोड़ दूंगा क्योंकि वे सभी विरासत के पेड़ से ऊपर आने लगते हैं –

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

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