2010-08-02 13 views
5

एक typeglob देखते हुए, मैं जो प्रकार वास्तव में परिभाषित कर रहे हैं कि कैसे मिल सकती है?पर्ल: से अधिक पुनरावृति एक typeglob

अपने आवेदन में, हम एक सरल विन्यास प्रारूप के रूप में PERL उपयोगकर्ता। मैं उपयोगकर्ता कॉन्फ़िगरेशन फ़ाइल() की आवश्यकता है, फिर यह देखने में सक्षम होना चाहिए कि कौन से चर परिभाषित किए गए हैं, साथ ही साथ वे किस प्रकार हैं।

कोड: (संदिग्ध गुणवत्ता सलाहकार)

#!/usr/bin/env perl 

use strict; 
use warnings; 

my %before = %main::; 
require "/path/to/my.config"; 
my %after = %main::; 

foreach my $key (sort keys %after) { 
    next if exists $before{$symbol}; 

    local *myglob = $after{$symbol}; 
    #the SCALAR glob is always defined, so we check the value instead 
    if (defined ${ *myglob{SCALAR} }) { 
     my $val = ${ *myglob{SCALAR} }; 
     print "\$$symbol = '".$val."'\n" ; 
    } 
    if (defined *myglob{ARRAY}) { 
     my @val = @{ *myglob{ARRAY} }; 
     print "\@$symbol = ('". join("', '", @val) . "')\n" ; 
    } 
    if (defined *myglob{HASH}) { 
     my %val = %{ *myglob{HASH} }; 
     print "\%$symbol = ("; 
     while( my ($key, $val) = each %val) { 
      print "$key=>'$val', "; 
     } 
     print ")\n" ; 
    } 
} 

my.config:

@A = (a, b, c); 
%B = (b=>'bee'); 
$C = 'see'; 

उत्पादन:

@A = ('a', 'b', 'c') 
%B = (b=>'bee',) 
$C = 'see' 
$_<my.config = 'my.config' 
+0

क्या आपका वर्तमान कोड स्निपेट आपके लिए काम कर रहा है? यदि नहीं, तो क्या आपके पास एक साधारण नमूना कॉन्फ़िगरेशन फ़ाइल है जिसे आप पोस्ट कर सकते हैं? –

+0

@ अणुओं मैंने एक नमूना विन्यास जोड़ा है। यह सिर्फ बहुत ही सरल पर्ल है। – bukzor

+0

@ अणुओं: यदि मैं इसे सही ढंग से समझता हूं, तो इसका मतलब है कि मुझे हमेशा स्केलर्स के लिए झूठी सकारात्मकता मिलती है, लेकिन फिर मैं जांच सकता हूं कि मान अनिश्चित है, और मुझे अभी भी ARRAY और HASH का पता लगाने में सक्षम होना चाहिए। – bukzor

उत्तर

7

पूरी तरह से सामान्य स्थिति में, आप क्या नहीं कर सकते आप perlref से निम्नलिखित अंश करने के लिए धन्यवाद करना चाहते हैं:

*foo{THING}undef लौटाता है यदि स्केलर्स के मामले में छोड़कर उस विशेष चीज का अभी तक उपयोग नहीं किया गया है। *foo{SCALAR} एक अज्ञात स्केलर का संदर्भ देता है यदि $foo अभी तक उपयोग नहीं किया गया है। यह भविष्य की रिलीज में बदल सकता है।

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

#! /usr/bin/perl 

use strict; 
use warnings; 

open my $fh, "<", \$_; # get DynaLoader out of the way 

my %before = %main::; 
require "my.config"; 
my %after = %main::; 

foreach my $name (sort keys %after) { 
    unless (exists $before{$name}) { 
    no strict 'refs'; 
    my $glob = $after{$name}; 
    print "\$$name\n"    if defined ${ *{$glob}{SCALAR} }; 
    print "\@$name\n"    if defined *{$glob}{ARRAY}; 
    print "%$name\n"    if defined *{$glob}{HASH}; 
    print "&$name\n"    if defined *{$glob}{CODE}; 
    print "$name (format)\n"  if defined *{$glob}{FORMAT}; 
    print "$name (filehandle)\n" if defined *{$glob}{IO}; 
    } 
} 

के रूप में तुम वहाँ मिल जाएगा।

$JACKPOT = 3_756_788; 
$YOU_CANT_SEE_ME = undef; 

@OPTIONS = qw/ apple cherries bar orange lemon /; 

%CREDITS = (1 => 1, 5 => 6, 10 => 15); 

sub is_jackpot { 
    local $" = ""; # " fix Stack Overflow highlighting 
    "@_[0,1,2]" eq "barbarbar"; 
} 

open FH, "<", \$JACKPOT; 

format WinMessage = 
You win! 
. 

उत्पादन का my.config साथ

%CREDITS 
FH (filehandle) 
$JACKPOT 
@OPTIONS 
WinMessage (format) 
&is_jackpot

नाम मुद्रण एक छोटे से काम लेता है, लेकिन हम बोझ के भाग लेने के लिए Data::Dumper मॉड्यूल का उपयोग कर सकते हैं। सामने बात समान है:

#! /usr/bin/perl 

use warnings; 
use strict; 

use Data::Dumper; 
sub _dump { 
    my($ref) = @_; 
    local $Data::Dumper::Indent = 0; 
    local $Data::Dumper::Terse = 1; 
    scalar Dumper $ref; 
} 

open my $fh, "<", \$_; # get DynaLoader out of the way 

my %before = %main::; 
require "my.config"; 
my %after = %main::; 

हम कुछ अलग ढंग से विभिन्न स्लॉट्स डंप करने की जरूरत है और प्रत्येक मामले में संदर्भ से घिरे होने निकालें: %before के बीच सेट अंतर से अधिक

my %dump = (
    SCALAR => sub { 
    my($ref,$name) = @_; 
    return unless defined $$ref; 
    "\$$name = " . substr _dump($ref), 1; 
    }, 

    ARRAY => sub { 
    my($ref,$name) = @_; 
    return unless defined $ref; 
    for ("\@$name = " . _dump $ref) { 
     s/= \[/= (/; 
     s/\]$/)/; 
     return $_; 
    } 
    }, 

    HASH => sub { 
    my($ref,$name) = @_; 
    return unless defined $ref; 
    for ("%$name = " . _dump $ref) { 
     s/= \{/= (/; 
     s/\}$/)/; 
     return $_; 
    } 
    }, 
); 

अंत में, हम पाश और %after:

foreach my $name (sort keys %after) { 
    unless (exists $before{$name}) { 
    no strict 'refs'; 
    my $glob = $after{$name}; 
    foreach my $slot (keys %dump) { 
     my $var = $dump{$slot}(*{$glob}{$slot},$name); 
     print $var, "\n" if defined $var; 
    } 
    } 
} 

अपने प्रश्न से my.config का उपयोग करना, उत्पादन

01 है
$ ./prog.pl 
@A = ('a','b','c') 
%B = ('b' => 'bee') 
$C = 'see'
+1

मैंने अभी देखा कि 'पैकेज :: स्टैश' क्या करता है, और यह स्पष्ट कामकाज के साथ जाता है: स्केलर को देखते समय यह ग्लोब से स्केलरफ्रैफ़ को संदर्भित करता है और देखता है कि स्केलर परिभाषित किया गया है या नहीं। तो अगर किसी कारण से आप एक स्केलर बनाते हैं लेकिन इसमें अनदेखा छोड़ देते हैं, तो यह दिखाई नहीं देगा, लेकिन कम से कम कल्पित स्केलर रास्ते में नहीं आते हैं। – hobbs

+0

@ हॉब्स: एक अपरिभाषित स्केलर और अनावृत मूल्य वाले स्केलर के बीच का अंतर सबसे अच्छा है। मैं उन्हें एक ही श्रेणी में लंपने के साथ ठीक हूं। – bukzor

+0

काफी अच्छा है। यदि आप आउटपुट में मान जोड़ देंगे, तो मैं इस जवाब को स्वीकार करूंगा और उपरोक्त अपना बदसूरत प्रयास हटा दूंगा। – bukzor

1

अद्यतन:
gbacon सही है। * ग्लोब {SCALAR} परिभाषित किया गया है।

Name "main::glob" used only once: 
possible typo at 
test_glob_foo_thing.pl line 13. 
'FOO1' (SCALAR) 
'FOO1' (GLOB) 
'FOO2' (SCALAR) 
'FOO2' (GLOB) 
'_<my.config' (SCALAR) 
'_<my.config' (GLOB) 

यह वह जगह है foo2 के बावजूद एक हैश के रूप में परिभाषित किया जा रहा है, लेकिन एक अदिश के रूप में नहीं:

यहाँ उत्पादन मैं अपने कोड का उपयोग करने के लिए है।

मूल जवाब:

अगर मैं तुम्हें सही ढंग से समझ, तो आप बस defined में निर्मित उपयोग करने के लिए की जरूरत है।

#!/usr/bin/env perl 

use strict; 
use warnings; 

my %before = %main::; 
require "/path/to/my.config"; 
my %after = %main::; 

foreach my $key (sort keys %after) { 
    if (not exists $before{$key}) { 
     if(defined($after{$key}){ 
      my $val = $after{$key}; 
      my $what = ref($val); 
      print "'$key' ($what)\n"; 
     } 
    } 
} 
3

5.010 में शुरू होने से, आप अंतर कर सकते हैं कि स्केलर बी इंट्रोसक्शन मॉड्यूल का उपयोग कर रहा है या नहीं; देख Detecting declared package variables in perl

अद्यतन: उदाहरण है कि इसका जवाब से नकल:

# package main; 
our $f; 
sub f {} 
sub g {} 

use B; 
use 5.010; 
if (${ B::svref_2object(\*f)->SV }) { 
    say "f: Thar be a scalar tharrr!"; 
} 
if (${ B::svref_2object(\*g)->SV }) { 
    say "g: Thar be a scalar tharrr!"; 
} 

1; 
+0

मैं उस धागे या बी दस्तावेज से ज्यादा हासिल करने में सक्षम नहीं था। क्या आपके पास एक संक्षिप्त उदाहरण है? – bukzor

+0

@ बुकर: लिंक किए गए उत्तर से उदाहरण की प्रतिलिपि बनाई; क्या कुछ और था? एसवी विधि एसवी स्लॉट में शून्य मूल्य के लिए बी :: विशेष वस्तु वापस कर देगी, लेकिन उस वर्ग का उपयोग कुछ अन्य विशेष मूल्यों के लिए भी किया जाता है और यह निर्धारित करने के लिए अच्छी विधियां प्रदान नहीं करता है कि यह कौन सा है, लेकिन चूंकि बी ऑब्जेक्ट्स हैं संख्यात्मक वास्तविक पते को संग्रहित स्केलरों के लिए केवल धन्य संदर्भ, आप 0 या नहीं होने पर परीक्षण कर सकते हैं और परीक्षण कर सकते हैं। – ysth

+0

मैं वास्तव में एक अजगर आदमी हूँ। मुझे नहीं पता कि इसका क्या मतलब है। – bukzor

3

कार्य कोड एक CPAN मॉड्यूल कि जिस तरह से, Package::Stash से बाहर बाल में से कुछ हो जाता है का उपयोग कर। जैसा कि gbacon के उत्तर में मेरी टिप्पणी में उल्लेख किया गया है, यह $someval = undef पर कॉन्फ़िगरेशन फ़ाइल के लिए अंधेरा है लेकिन यह अपरिहार्य प्रतीत होता है, और कम से कम अन्य मामले पकड़े जाते हैं। यह भी SCALAR, सरणी, हैश, कोड के लिए खुद को सीमित करता है, और आईओ प्रकार - हो रही GLOB और प्रारूप के लिए संभव है, लेकिन यह कोड कम सुंदर बनाता है और यह भी उत्पादन :)

#!perl 

use strict; 
use warnings; 

use Package::Stash; 

sub all_vars_in { 
    my ($package) = @_; 
    my @ret; 

    my $stash = Package::Stash->new($package); 
    for my $sym ($stash->list_all_package_symbols) { 
    for my $sigil (qw($ @ % &), '') { 
      my $fullsym = "$sigil$sym"; 
     push @ret, $fullsym if $stash->has_package_symbol($fullsym); 
    } 
    } 
    @ret; 
} 

my %before; 
$before{$_} ++ for all_vars_in('main'); 

require "my.config"; 

for my $var (all_vars_in('main')) { 
    print "$var\n" unless exists $before{$var}; 
} 
0

आप तो में शोर पैदा करता है पार्सिंग डेटा को ध्यान में रखें :: डंप आउटपुट, आप अंतर को छेड़छाड़ करने के लिए इसका इस्तेमाल कर सकते हैं।

use strict; 
use warnings; 
use Data::Dump qw{ dump }; 

my %before = %main::; 
require "my.config"; 
my %after = %main::; 

foreach my $key (sort keys %after) { 
    if (not exists $before{$key}) { 
     my $glob = $after{$key}; 
     print "'$key' " . dump($glob) . "\n"; 
    } 
} 

निम्नलिखित कॉन्फ़िग फ़ाइल के साथ इस कोड का उपयोग करना:

$FOO1 = 3; 
$FOO2 = 'my_scalar'; 
%FOO2 = (a=>'b', c=>'d'); 
@FOO3 = (1 .. 5); 
$FOO4 = [ 1 .. 5 ]; 

मुझे विश्वास है कि इस उत्पादन प्रत्येक प्रकार ग्लोब की जो भागों यह पता लगाने के लिए सक्षम हो करने के लिए पर्याप्त जानकारी प्रदान करता है परिभाषित कर रहे हैं:

'FOO1' do { 
    my $a = *main::FOO1; 
    $a = \3; 
    $a; 
} 
'FOO2' do { 
    my $a = *main::FOO2; 
    $a = \"my_scalar"; 
    $a = { a => "b", c => "d" }; 
    $a; 
} 
'FOO3' do { 
    my $a = *main::FOO3; 
    $a = [1 .. 5]; 
    $a; 
} 
'FOO4' do { 
    my $a = *main::FOO4; 
    $a = \[1 .. 5]; 
    $a; 
} 
'_<my.config' do { 
    my $a = *main::_<my.config; 
    $a = \"my.config"; 
    $a; 
} 
1

मुझे पूछने से नफरत है, लेकिन टाइपग्लब्स के साथ गड़बड़ करने की बजाय, वास्तविक कॉन्फ़िगरेशन प्रारूप पर क्यों न स्विच करें? जैसे Config::Simple और YAML देखें।

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

भी देखें आत्म noosify और आत्म टाई के आसपास-your-गर्दन के लिए काफी खुश भी है: How do you manage configuration files in Perl?

+0

मेरे उपयोगकर्ताओं को सरल PERL पता होना चाहिए। उस समय, हमने सोचा कि यह चीजों को कॉन्फ़िगर करने का एक आसान तरीका होगा, लेकिन शायद हम गलत थे। सतह पर कॉन्फ़िगर बहुत अच्छा लग रहा है, इसलिए यह तब तक नहीं बदलेगा जब तक कि मैं प्रबंधन के लिए आधिकारिक तर्क प्रस्तुत नहीं कर सकता। – bukzor

+1

+1। अच्छी नौकरी को वास्तविक जरूरत के लिए प्रश्न से पहले देख रहे हैं। –

1
no strict 'refs'; 
my $func_name = 'myfunc'; 
*{$func_name}{CODE}() 
use strict 'refs'; 
संबंधित मुद्दे