2010-05-22 10 views
5

मैं पर्ल को "हेड-फर्स्ट" तरीके से सीख रहा हूं। मैं इस भाषा में बिल्कुल नौसिखिया हूं:मैं अपने पर्ल प्रोग्राम के लिए कमांड लाइन स्विच के माध्यम से एक डिबगिंग मोड कैसे सक्षम कर सकता हूं?

मैं सीएलआई से डीबग_मोड स्विच करने की कोशिश कर रहा हूं जिसका उपयोग कुछ स्प्रॉउटिन को "चालू और बंद" स्विच करके नियंत्रित करने के लिए किया जा सकता है।

और नीचे क्या मैं अब तक मिल गया है है: तो जहाँ तक मैं बता सकता हूँ

#!/usr/bin/perl -s -w 

# purpose : make subroutine execution optional, 
# which is depending on a CLI switch flag 

use strict; 
use warnings; 

use constant DEBUG_VERBOSE    => "v"; 
use constant DEBUG_SUPPRESS_ERROR_MSGS => "s"; 
use constant DEBUG_IGNORE_VALIDATION  => "i"; 
use constant DEBUG_SETPPING_COMPUTATION => "c"; 

our ($debug_mode); 

mainMethod(); 

sub mainMethod #() 
{ 
    if(!$debug_mode) 
    { 
     print "debug_mode is OFF\n"; 
    } 
    elsif($debug_mode) 
    { 
     print "debug_mode is ON\n"; 
    } 
    else 
    { 
     print "OMG!\n"; 
     exit -1; 
    } 

    checkArgv(); 
    printErrorMsg("Error_Code_123", "Parsing Error at..."); 
    verbose(); 
} 

sub checkArgv #() 
{ 
    print ("Number of ARGV : ".(1 + $#ARGV)."\n"); 
} 

sub printErrorMsg # ($error_code, $error_msg, ..) 
{ 
    if(defined($debug_mode) && !($debug_mode =~ DEBUG_SUPPRESS_ERROR_MSGS)) 
    { 
     print "You can only see me if -debug_mode is NOT set". 
      " to DEBUG_SUPPRESS_ERROR_MSGS\n"; 
     die("terminated prematurely...\n") and exit -1; 
    } 
} 

sub verbose #() 
{ 
    if(defined($debug_mode) && ($debug_mode =~ DEBUG_VERBOSE)) 
    { 
     print "Blah blah blah...\n"; 
    } 
} 

, कम से कम यह काम करता है ...:

  1. -debug_mode स्विच नहीं करता है 'टी सामान्य ARGV
  2. निम्नलिखित commandlines काम के साथ हस्तक्षेप:
    • ./option al.pl
    • ./optional.pl -debug_mode
    • ./optional.pl -debug_mode = वी
    • ./optional.pl -debug_mode = रों

हालांकि, मैं बजे, हैरान जैसे जब कई debug_modes "मिश्रित" कर रहे हैं:

  1. ./optional.pl -debug_mode = sv
  2. ./optional.pl -debug_mode = बनाम

मुझे समझ में नहीं आता कि कोड की उपरोक्त पंक्तियां "जादुई रूप से काम करती हैं" क्यों।

मुझे लगता है कि "DEBUG_VERBOS" और "DEBUG_SUPPRESS_ERROR_MSGS" दोनों स्क्रिप्ट पर लागू होते हैं, जो इस मामले में ठीक है।

हालांकि, अगर कुछ "विरोधाभासी" डीबग मोड हैं, तो मुझे यकीन नहीं है कि "डीबग_मोड्स की प्राथमिकता" को कैसे सेट किया जाए?

इसके अलावा, मुझे यकीन नहीं है कि मेरा दृष्टिकोण पर्लिस्टों के लिए पर्याप्त है और मुझे उम्मीद है कि मैं अपने पैरों को सही दिशा में प्राप्त कर रहा हूं।

एक सबसे बड़ी समस्या यह है कि अब मैं अलग-अलग तरीकों के तहत अपने व्यवहार को नियंत्रित करने के लिए के अधिकांश वक्तव्य डालता हूं। यह ठीक है? क्या कोई और शानदार तरीका है?

मुझे पता है कि सीपीएएन या अन्य जगहों से डीबग मॉड्यूल होना चाहिए, लेकिन मुझे एक वास्तविक न्यूनतम समाधान चाहिए जो "डिफ़ॉल्ट" से किसी अन्य मॉड्यूल पर निर्भर न हो।

और मैं वातावरण जहां इस स्क्रिप्ट निष्पादित किया जाएगा पर कोई नियंत्रण नहीं कर सकते हैं ...

+1

पर्ल गुरु आपको भाषा को 'पर्ल' के रूप में संदर्भित करना पसंद करेंगे, न कि 'PERL' – Zaid

+1

बहुत अधिक सुरुचिपूर्ण तरीके हैं, लेकिन चूंकि आप बस पर्ल सीखना शुरू कर रहे हैं, इसे सभी को समझाने में काफी समय लगेगा। बस मेरी सभी किताबें पढ़ें। वास्तव में। _Learning Perl_ आपको मूल बातें सिखाता है, _Intermediate Perl_ आपको संदर्भ और ऑब्जेक्ट सामग्री देता है, और फिर आप _Mastering Perl_ के लिए तैयार हैं जो दिखाता है कि आप करना चाहते हैं। कॉन्फ़िगरेशन और लॉगिंग के लिए समर्पित अध्याय हैं। –

+0

बूल के पास तीसरा मान नहीं हो सकता है, इसलिए उस सशर्त जांच '$ debug_mode' पर एक और डालना बल्कि बेकार है। – Ether

उत्तर

6

कमांड लाइन विकल्पों को संभालने के लिए, Getopt::Long पर एक नज़र डालें। आपको सभी तरह के स्लिम तर्क पार्सिंग विकल्प मिलते हैं।

लॉगिंग को संभालने वाले कई मॉड्यूल हैं। Log4Perl एक बहुत ही लोकप्रिय लॉगिंग मॉड्यूल है।

यदि आप वास्तव में, वास्तव में CPAN (जो एक बुरा विचार है) से बचकर खुद को सीमित करना चाहते हैं तो आप लॉगिंग मॉड्यूल को आसानी से हैक कर सकते हैं।

यहां एक छोटा सा है जिसे मैंने आपके लिए हैक किया है। इसे परीक्षण और वास्तविक दस्तावेज़ों की आवश्यकता है और आगे। मैंने कस्टम import() विधि जैसी कुछ उन्नत तकनीकों का भी उपयोग किया। पूरे ऐप के लिए DEBUG सेटिंग्स को स्टोर करने के लिए एक चर के उपयोग के आस-पास कुछ गठिया भी हैं। लेकिन यह काम करता है। मैंने एक परियोजना पर एक समान मॉड्यूल का इस्तेमाल किया और इसके साथ बहुत खुश था।

package QLOG; 

use strict; 
use warnings; 
use Carp qw(croak); 

our %DEBUG_OPTIONS; 
our %VALID_DEBUG_OPTIONS; 
our %DEBUG_CONFLICTS; 

sub import { 

    my $pkg = shift; 
    my $target = caller(); 

    my %opts = @_; 


    # Configure options 

    croak "Must supply an array ref of valid modes" 
     unless exists $opts{options}; 

    @VALID_DEBUG_OPTIONS{ @{$opts{options}} } =(); 

    # Configure conflicts 

    if(exists $opts{conflicts}) { 
     @DEBUG_CONFLICTS{ keys %{$opts{conflicts}} } 
      = values %{$opts{conflicts}} 
    } 

    # Export DEBUG method 

    { no strict 'refs'; 
     *{$target.'::DEBUG'} = \&DEBUG; 
    } 

    return; 
} 

sub DEBUG { 
    my $mode = shift; 

    croak "DEBUG mode undefined" 
     unless defined $mode; 

    return unless 
     ($mode eq 'ANY' and %DEBUG_OPTIONS) 
     or exists $DEBUG_OPTIONS{$mode}; 

    warn "$_\n" for @_; 

    return 1; 
} 


sub set_options { 

    for my $opt (@_) { 
     die "Illegal option '$opt'" 
      unless exists $VALID_DEBUG_OPTIONS{$opt}; 

     $DEBUG_OPTIONS{$opt}++; 
    } 

    return; 
} 

sub check_option_conflicts { 

    for my $opt (keys %DEBUG_OPTIONS) { 

     if (exists $DEBUG_CONFLICTS{$opt}) { 

      for (@{$DEBUG_CONFLICTS{$opt}}) { 

       die "Debug option $opt conflicts with $_" 
        if exists $DEBUG_OPTIONS{$_} 
      } 
     } 
    } 

    return; 
} 


1; 

और फिर इस तरह इसका इस्तेमाल:

#!/usr/bin/perl 

use strict; 
use warnings; 


use Getopt::Long; 

use QLOG 
    options => [qw(
     VERBOSE 
     SUPPRESS_ERROR_MSGS 
     IGNORE_VALIDATION 
     SETPPING_COMPUTATION 
    )], 
    conflicts => { 
     VERBOSE => [qw(
      SUPPRESS_ERROR_MSGS 
      SETPPING_COMPUTATION 
     )], 
    }; 




process_args(); 

DEBUG VERBOSE => 'Command line data parsed.'; 

main(); 

### --------------- 

sub main { 

    DEBUG VERBOSE => 'BEGIN main()'; 

    if(DEBUG 'ANY') { 
     print "debug_mode is ON\n"; 
    } 
    else { 
     print "debug_mode is OFF\n"; 
    } 

    warn "Error which could be surpressed\n" 
     unless DEBUG 'SUPPRESS_ERROR_MSGS'; 
} 


# Get arguments and process flags like 'v' and 'sc' into strings specified 
# in QLOG configuration above. 
# This processing makes the nice DEBUG VERBOSE => 'blah'; syntax work. 
sub process_args { 

    # Use Getopt::Long to parse @ARGV 

    my @debug_options; 
    GetOptions (
     '[email protected]' => \@debug_options, 
     'help'    => \&usage, 
    ) or usage(); 

    # Convert option flags to strings. 
    my %option_lut = qw(
     v VERBOSE 
     s SUPPRESS_ERROR_MSGS 
     i IGNORE_VALIDATION 
     c SETPPING_COMPUTATION 
    ); 

    my @options = map {   # This chained map 
     exists $option_lut{$_} # looks in the lut for a flag 
     ? $option_lut{$_}  #  translates it if found 
     : $_      #  or passes on the original if not. 
    } 
    map {      # Here we split 'cv' into ('c','v') 
     split // 
    } @debug_options; 

    # Really should use Try::Tiny here. 
    eval {  
     # Send a list of strings to QLOG 
     # QLOG will make sure they are allowed. 
     QLOG::set_options(@options); 

     QLOG::check_option_conflicts(); 

     1;   # Ensure true value returned if no exception occurs. 
    } or usage([email protected]); 

    return; 
} 

sub usage { 

    my $message = shift || ''; 
    $message = '' if $message eq 'help'; 

    print <<"END"; 
$message 

Use this proggy right. 

END 

    exit; 
} 

आप अपने डिबग संदेशों suppressable बनाने के लिए एक विधि को जोड़ने के लिए चाहते हो सकता है।

कुछ की तरह:

sub SUPPRESSED_BY { 
    my $mode = shift; 

    return if exists $DEBUG_OPTIONS{$mode); 

    return @_; 
} 

निर्यात प्रतीक और उसके बाद का उपयोग करें इसे पसंद:

DEBUG VERBOSE => SUPPRESSED_BY SUPPRESS_ERRORS => 'My message here'; 

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

किसी भी तरह, यह आपको पानी में एक गंभीर डंक देना चाहिए क्योंकि आप पहली बार पर्ल में सिर डाइव करते हैं।

मुझसे पूछने के लिए स्वतंत्र महसूस करें कि 'बिल्ली क्या है?' प्रश्न टाइप करें। मुझे एहसास है कि मैं आप पर बहुत फेंक रहा हूँ।

+1

@daotoad: आपके उत्कृष्ट उत्तर के लिए धन्यवाद। मैं और अधिक नहीं पूछ सकता :) और स्पष्ट रूप से बोलते हुए मुझे नहीं लगता कि अब मेरे लिए "बिल्ली क्या है?" पूछने का उचित समय है प्रश्नों के प्रकार - मैं ऊंट की किताब को बेहतर तरीके से पकड़ूंगा और पेज 1 से इसे पढ़ना शुरू कर दूंगा। सिर की पहली शुरुआत पाने के लिए मैंने एक और पुस्तक "मिनिमल पर्ल" का इस्तेमाल किया। अब मुझे लगता है कि मुझे बुनियादी बातों से भाषा को समझने के लिए कुछ समय चाहिए :) –

+1

@ माइकल, आरटीएफएम/आरटीएफबी एक बिंदु तक अच्छा है। लेकिन अक्सर सही प्रश्न पूछकर एक घंटे बचाया जा सकता है। साथ ही, यह ध्यान देने योग्य है कि ऊंट को अद्यतन की गंभीर आवश्यकता है। उदाहरण के लिए, यह छद्म-हैश का उपयोग करने की सिफारिश करता है जिसे 5.8 में हटा दिया गया था और 5.10 में हटा दिया गया था। हालांकि, यह अभी भी एक अच्छी किताब का नरक है। – daotoad

+0

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

1

मुझे लगता है कि तुम यहाँ दो मुद्दों का सामना कर रहे। सबसे पहले, अधिक जटिल कमांड लाइन पार्सिंग को संभालने के लिए, -s कमांड लाइन स्विच के बजाय कोर Getopt::Std या Getopt::Long मॉड्यूल का उपयोग करें।

दूसरा मुद्दा (मुझे लगता है) यह है कि जब आप डीबग मोड सक्षम होते हैं तो आप अपने डीबग स्टेटमेंट को छोड़ने के लिए कुछ जादू तरीका रखने की कोशिश कर रहे हैं।मैं किसी भी मानक मॉड्यूल है कि करता है के बारे में पता नहीं कर रहा हूँ, लेकिन यह विभिन्न प्रकार के निर्माणों के साथ संभव है:

eval { ...code block... } if($debug); 

यह यह जरूरी है मतलब यह नहीं है एक अच्छा विचार है कि क्या डिबग मोड पर अपने कार्यक्रम के तर्क के आधार को बदलने के लिए सक्षम किया गया है। आपको तर्क के बजाए अपने प्रोग्राम के आउटपुट को बदलने के लिए "डीबग मोड" को सीमित करना चाहिए, या आप यह सोचने में कई घंटे व्यतीत करेंगे कि यह डीबग मोड में क्यों काम करता है, न कि 'उत्पादन मोड' में।

+0

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

2

टोर के प्रति आपकी प्रतिक्रिया के आधार पर, मैंने इस नमूना को हैक किया।

#!/usr/bin/perl 

use strict; 
use warnings; 

use Getopt::Long; 

my $count_letters; 
my $eat_beans; 
my $count_beans; 
my $data_file; 

GetOptions (
    'count-letters' => \$count_letters, 
    'count-beans' => \$count_beans, 
    'eat-beans'  => \$eat_beans, 
    'data-file=s' => \$data_file, 
    'help'   => \&usage, 
) or usage(); 

# Build code ref arrays. 

my @validate_file = 
    ($count_beans ? \&count_beans :()), 
    ($count_letters ? \&count_letters :()), 
    ; 

my @validate_line = 
    ($eat_beans  ? \&eat_beans  :()), 
    ; 


process_file($data_file, \@validate_line, \@validate_file); 


sub process_file { 
    my $file   = shift; 
    my $validate_lines = shift; 
    my $validate_file = shift; 

    open my $fh, '<', $file or die "$file : $!"; 

    my @data; 
    while(my $line = $fh->readline) { 

     # Validate each line with each line validator 

     $_->($line) or die 'Invalid line' 
      for @$validate_lines; 

     push @data, $line; 
    } 

    # Validate the whole file with the each file validator. 
    $_->(\@data) or die 'Invalid file' 
     for @$validate_file; 
} 

# Put real subs here: 

sub eat_beans  { 1 } 

sub count_beans { 1 } 
sub count_letters { 1 } 

परीक्षण के लिए के रूप में, आप शायद एक मॉड्यूल में अपने सभी मान्यता बाद के चरणों में डाल दिया है और सामान्य पर्ल परीक्षण उपकरण का उपयोग करना चाहते (परीक्षण करें :: सरल और टेस्ट :: अधिक आरंभ करने के लिए)।

मुझे एक पतली सीएलआई पार्सर द्वारा मेरे ऐप्स को ढूढ़ना पसंद है जो मॉड्यूल में रहने वाले मुख्य ऐप तर्क द्वारा उपयोग किए जाने वाले अंतर्निहित डेटा सेट को कॉन्फ़िगर करता है।

यह सत्यापित करने के लिए यूनिट परीक्षण लिखना बहुत आसान बनाता है कि कोड अच्छा है।

+0

@daotoad: आपके दूसरे उत्तर के लिए बहुत बहुत धन्यवाद। और आपको मुझे एक बड़ा सवाल मिला है: मैं आपको दूसरा टिक नहीं दे सकता, क्या मैं कर सकता हूं? :) –

2

इस उत्तर देने के लिए:

मुझे समझ नहीं आता क्यों कोड की ऊपर लाइनों "जादुई काम करता है"।

कारण यह है कि आप एक नियमित अभिव्यक्ति के साथ डिबग स्विच के मूल्यों के लिए जाँच कर रहे हैं के रूप में, यह है:

if(defined($debug_mode) && !($debug_mode =~ DEBUG_SUPPRESS_ERROR_MSGS)) 

तो अगर आप हैं:

$debug_mode = "sv" 

और के रूप में एक अनुस्मारक:

use constant DEBUG_VERBOSE    => "v"; 
use constant DEBUG_SUPPRESS_ERROR_MSGS => "s"; 

तो ये दोनों ई सच का मूल्यांकन:

$debug_mode =~ DEBUG_SUPPRESS_ERROR_MSGS; 
$debug_mode =~ DEBUG_VERBOSE; 

आप आप कोशिश कर सकते हैं ठीक एक मूल्य के लिए जाँच करना चाहते हैं:

if ($debug_mode eq DEBUG_SUPPRESS_ERROR_MSGS) {...} 
if ($debug_mode eq DEBUG_VERBOSE) {...} 

वरना

if ($debug_mode =~ /\bDEBUG_SUPPRESS_ERROR_MSGS\b/) {...} 
if ($debug_mode =~ /\bDEBUG_VERBOSE/b\) {...} 

जहां \b regex एक शब्द सीमा से मिलान करने के लिए कहता है । बेशक, अगर आपके पास $debug_mode ="s v" है तो रेगेक्स भी सत्य का मूल्यांकन करेगा।

+0

: आपके स्पष्टीकरण के लिए धन्यवाद। मैंने "= ~" ऑपरेटर को "स्ट्रिंग तुलना के लिए ऑपरेटर" के रूप में गलत समझा है ... जादू मैं जिस तरह से हासिल करना चाहता था वह "दुर्घटना से" चाहता था :) –

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

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