2011-11-23 19 views
5

में परिवर्तनीय असाइनमेंट कैप्चर करें मैं एक पर्ल eval से परिवर्तनीय असाइनमेंट कैप्चर करने में सक्षम होना चाहूंगा। यही है, यह निर्धारित करने के लिए कि कोड के भीतर कौन से चर नाम निर्दिष्ट किए गए हैं और उनका मूल्य निकाला गया है।पर्ल eval

उदाहरण के लिए अगर मैं चलाएँ:

eval '$foo=42; $bar=3.14;' 

eval का परिणाम 3.14 (पिछले मूल्य का मूल्यांकन) है, लेकिन मैं भी नाम "$ foo" और निर्धारित करने में सक्षम होना चाहते हैं "$ बार "और उनके मूल्य (अग्रिम नामों को जानने के बिना)।

मैंने सुरक्षित और Eval :: संदर्भ के माध्यम से, eval ब्लॉक में चर डालने के कुछ तरीकों पर पढ़ा है, लेकिन अभी तक उन्हें निकालने का कोई तरीका नहीं है। मैं पाइथन के eval/exec से अधिक परिचित हूं जिसने इसके लिए समर्थन में बनाया है।

उत्तर

1

एरिक स्ट्रॉम द्वारा सुझाए गए अनुसार Safe के आधार पर समाधान निकालने का मेरा प्रयास यहां दिया गया है।

package main; 
use warnings; use strict; 
use Safe; 

my $cpt = new Safe; 

$cpt->permit_only(qw(sassign lineseq padany const rv2sv leaveeval)); 
my $name_space = $cpt->root; 

my $no_strict = 0; 
# 
# populate the clean symbol table 
# 
$cpt->reval('0'); 
die "safe compartment initialisation error: [email protected]" if [email protected]; 
my %symtab_clean = do {no strict 'refs'; %{$name_space.'::'} }; 

my $result = $cpt->reval('$foo=42; $bar=3.14;', $no_strict); 

if ([email protected]) { 
    warn "eval error: [email protected]"; 
} 
else { 
    # 
    # symbol table additions 
    # 
    my %symtab_dirty = do {no strict 'refs'; %{$name_space.'::'} }; 

    my @updated_variables = grep { ! exists $symtab_clean{$_} } (sort keys %symtab_dirty); 

    foreach my $variable (@updated_variables) { 
     my $value = do{ no strict 'refs'; ${$name_space.'::'.$variable} }; 
     print "variable $variable was set to: $value\n" 
    } 
} 

नोट्स:

  1. ऊपर एसएएफ opcodes का एक न्यूनतम restrictve सेट अनुमति देता है। perl opcodes
  2. देखें कि मैंने पहले मतभेद के लिए और आदेश
0

ठीक है, 0 fचलाने के बाद $ foo का मूल्य 42 होगा। उस क्षेत्र में कोई बदलाव नहीं है जो $ foo अदृश्य प्रदान करता है।

लेकिन यह निश्चित रूप से $ foo के अस्तित्व के बारे में पूर्व ज्ञान मानता है।

किसी भी मामले में, यह केवल use strict सेट के बिना काम करेगा, जो लगभग निश्चित रूप से एक बुरा विचार है। use strict जगह के साथ, स्क्रिप्ट संकलित नहीं होगा। मुझे लगता है कि आपका उदाहरण अधिक जटिल है, और आप अपने eval द्वारा किए गए मौजूदा हैश में बदलाव की तलाश में हैं। लेकिन यह स्पष्ट नहीं है कि आपके eval को यह नहीं पता था कि यह क्या बदल रहा था, जब तक कि कुछ प्रकार के गतिशील कोड इंजेक्शन चल रहे हों।

7

किसी भी eval के भीतर घोषित कोई भी व्याख्यात्मक चर eval समाप्त होने के बाद खो जाएगा। एक eval के भीतर सेट किए गए वैश्विक चर को कैप्चर और अलग करने के लिए, आप एक नया वैश्विक नामस्थान बनाने के लिए Safe मॉड्यूल का उपयोग करने में देख सकते हैं। निम्नलिखित की तरह कुछ:

use Safe; 

my $vars = Safe->new->reval(qq{ 
    $code_to_eval; 
    $code_to_search_the_symbol_table_for_declared_variables 
}); 

कहाँ खोज कोड कुछ ऐसा है जो नेस्टेड %main:: प्रतीक हित के किसी भी चर के लिए खोज तालिका चलता है के रूप में परिभाषित किया गया है। आप इसे जानकारी युक्त डेटा संरचना वापस कर सकते हैं, और उसके बाद आप जो भी चाहें उसके साथ कर सकते हैं।

आप रूट स्तर पर निर्धारित वेरिएबल के बारे में चिंतित हैं, तो आप की तरह कुछ लिख सकते हैं:

use strict; 
use warnings; 

my $eval_code = '$foo=42; $bar=3.14;'; 

use Safe; 
my $vars = Safe->new->reval(
    $eval_code . q{; 
    my %vars; 
    for my $name (keys %main::) { 
     next if $name =~ /::$/ # exclude packages 
     or not $name =~ /[a-z]/; # and names without lc letters 

     my $glob = $main::{$name}; 
     for (qw($SCALAR @ARRAY %HASH)) { 
      my ($sigil, $type) = /(.)(.+)/; 
      if (my $ref = *$glob{$type}) { 
       $vars{$sigil.$name} = /\$/ ? $$ref : $ref 
      } 
     } 
    } 
    \%vars 
}); 

print "$_: $$vars{$_}\n" for keys %$vars; 
# $foo: 42 
# $bar: 3.14 

खोज कोड भी peek_my उपयोग कर किसी भी निर्धारित वेरिएबल के लिए मौजूदा शाब्दिक गुंजाइश खोज करने के लिए Padwalker रोजगार सकता है समारोह।

+0

कौन-सा संस्करण पर्ल तार से ग्लोब स्लॉट तक पहुँचने के लिए अनुमति देता शुरू किया क्रियान्वित करने के बाद देखने के लिए चुना है? मैं शपथ ले सकता था कि मुझे ऐसा कुछ करने की कोशिश करने में "हैश नहीं" त्रुटि मिलती थी। तो, मुझे लगता है कि मुझे कुछ डेल्टा पेज पर याद किया होगा। – Axeman

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