मैं ऐसे प्रोग्राम पर काम कर रहा हूं जो अलग-अलग फाइलों में अलग-अलग सबरूटीन का उपयोग करता है।

तीन भाग हैं

  • सबरूटीन के नाम वाली एक टेक्स्ट फ़ाइल

  • सबरूटीन के साथ एक पर्ल कार्यक्रम

  • मुख्य कार्यक्रम जो सबरूटीन का नाम निकालता है और उसे लॉन्च करता है

सबरूटीन एक टेक्स्ट फ़ाइल से अपना डेटा लेता है।

मुझे टेक्स्ट फ़ाइल चुनने के लिए उपयोगकर्ता की आवश्यकता है, प्रोग्राम तब सबरूटीन का नाम निकालता है।

पाठ फ़ाइल में शामिल है

cycle.name=cycle01

यहाँ मुख्य कार्यक्रम है:

# !/usr/bin/perl -w

use strict;
use warnings;

use cycle01;

my $nb_cycle = 10;

# The user chooses a text file

print STDERR "\nfilename: ";

chomp($filename = <STDIN>);

# Extract the name of the cycle 

open (my $fh, "<", "$filename.txt") or die "cannot open $filename";

while ( <$fh> ) {

    if ( /cycle\.name/ ) {

        (undef, $cycleToUse) = split /\s*=\s*/;
    }
}

# I then try to launch the subroutine by passing variables.
# This fails because the subroutine is defined as a variable.

$cycleToUse($filename, $nb_cycle);

और यहाँ एक अन्य फ़ाइल में सबरूटीन है

# !/usr/bin/perl

package cycle01;

use strict;
use warnings;

sub cycle01 {

    # Get the total number of arguments passed
    my ($filename, $nb_cycle) = @_;
    print "$filename, $nb_cycle";
1
chocovore17 12 जुलाई 2018, 15:26

2 जवाब

सबसे बढ़िया उत्तर

आपका कोड संकलित नहीं होता है, क्योंकि अंतिम कॉल में, आपने $nb_cycle का नाम गलत टाइप कर दिया है। यदि आप कोड पोस्ट करते हैं जो वास्तव में चलता है तो यह सहायक होता है :-)

परंपरागत रूप से, पर्ल मॉड्यूल नाम एक बड़े अक्षर से शुरू होते हैं, इसलिए हो सकता है कि आप अपने पैकेज का नाम बदलकर Cycle01 करना चाहें।

ऐसा करने का त्वरित और गंदा तरीका eval के स्ट्रिंग संस्करण का उपयोग करना है। लेकिन कोड वाली एक मनमानी स्ट्रिंग का मूल्यांकन करना खतरनाक है, इसलिए मैं आपको वह नहीं दिखाने जा रहा हूं। डिस्पैच टेबल का उपयोग करने का सबसे अच्छा तरीका है - मूल रूप से एक हैश जहां कुंजियाँ मान्य सबरूटीन नाम हैं और मान स्वयं सबरूटीन के संदर्भ हैं। इसे जोड़ने के लिए सबसे अच्छी जगह Cycle01.pm फ़ाइल में है:

our %subs = (
  cycle01 => \&cycle01,
);

फिर, आपके कार्यक्रम का अंत बन जाता है:

if (exists $Cycle01::subs{$cycleToUse}) {
  $Cycle01::subs{$cycleToUse}->($filename, $nb_cycle);
} else {
  die "$cycleToUse is not a valid subroutine name";
}

(ध्यान दें कि जब आप उन्हें अपने while लूप में पढ़ते हैं तो आपको chomp() लाइनों की भी आवश्यकता होगी।)

4
Dave Cross 12 जुलाई 2018, 16:06

डेव क्रॉस के उत्तर पर निर्माण करने के लिए, मैं आमतौर पर हैश टेबल से बचता हूं, आंशिक रूप से क्योंकि, पर्ल में, वैसे भी सब कुछ हैश टेबल है। इसके बजाय, मेरे पास मेरे सभी प्रवेश-बिंदु उप एक विशेष उपसर्ग के साथ शुरू होते हैं, यह उपसर्ग इस बात पर निर्भर करता है कि मैं क्या कर रहा हूं, लेकिन यहां हम प्रवेश-बिंदु के लिए केवल ep_ का उपयोग करेंगे। और फिर मैं ऐसा कुछ करता हूं:

my $subname = 'ep_' . $cycleToUse;
if (my $func = Cycle01->can($subname))
{
  $func->($filename, $nb_cycle);
}
else
{
  die "$cycleToUse is not a valid subroutine name";
}

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

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

जैसे,

die "Invalid namespace $cycleNameSpaceToUse"
  if $cycleNameSpaceToUse =~ /::|'/;
my $ns = 'UserCallable::' . $cycleNameSpaceToUse;
my $subname = 'ep_' . $cycleToUse;
if (my $func = $ns->can($subname))
# ... as before

इसे दूसरे तरीके से करने के निश्चित रूप से फायदे हैं, जैसे कि आप जो उजागर करना चाहते हैं उसके बारे में स्पष्ट होना। यहां एक अलग सूची न रखने का फायदा है। मैं ऐसा करने में हमेशा भयानक हूं।

1
Tanktalus 12 जुलाई 2018, 18:47