2009-12-02 11 views
8

मुझे यकीन है कि यह कहीं भी प्रलेखन में शामिल है लेकिन मैं इसे खोजने में असमर्थ हूं ... मैं सिंटैक्टिक चीनी की तलाश में हूं जो कक्षा में एक विधि को कॉल करना संभव बनाता है जिसका नाम किसी संग्रह में संग्रहीत है हैश (के रूप में एक सरल अदिश के खिलाफ):मैं फ़ंक्शन में हैश में संग्रहीत फ़ंक्शन नाम कैसे कॉल करूं?

use strict; use warnings; 

package Foo; 
sub foo { print "in foo()\n" } 

package main; 
my %hash = (func => 'foo'); 

Foo->$hash{func}; 

अगर मैं एक अदिश चर में $hash{func} कॉपी पहले, तो मैं Foo->$func ठीक कॉल कर सकते हैं ... लेकिन क्या काम करने के लिए Foo->$hash{func} सक्षम करने के लिए याद आ रही है?

(संपादित करें: मुझे कक्षा Foo पर एक विधि को कॉल करके कुछ भी विशेष करने का मतलब नहीं है - यह आसानी से एक धन्य वस्तु (और मेरे वास्तविक कोड में) हो सकता है; यह लिखना आसान था एक वर्ग विधि का उपयोग कर एक आत्मनिर्भर उदाहरण।)

संपादित करें 2: बस पूर्ण टिप्पणियों के लिए नीचे दी गई टिप्पणियों के लिए, यह वही है जो मैं वास्तव में कर रहा हूं (यह मूस विशेषता चीनी की लाइब्रेरी में है, Moose::Exporter के साथ बनाया गया है) :

# adds an accessor to a sibling module 
sub foreignTable 
{ 
    my ($meta, $table, %args) = @_; 

    my $class = 'MyApp::Dir1::Dir2::' . $table; 
    my $dbAccessor = lcfirst $table; 

    eval "require $class" or do { die "Can't load $class: [email protected]" }; 

    $meta->add_attribute(
     $table, 
     is => 'ro', 
     isa => $class, 
     init_arg => undef, # don't allow in constructor 
     lazy => 1, 
     predicate => 'has_' . $table, 
     default => sub { 
      my $this = shift; 
      $this->debug("in builder for $class"); 

      ### here's the line that uses a hash value as the method name 
      my @args = ($args{primaryKey} => $this->${\$args{primaryKey}}); 
      push @args, (_dbObject => $this->_dbObject->$dbAccessor) 
       if $args{fkRelationshipExists}; 

      $this->debug("passing these values to $class -> new: @args"); 
      $class->new(@args); 
     }, 
    ); 
} 

मैं इस के साथ ऊपर चिह्नित लाइन बदल दिया है:

 my $pk_accessor = $this->meta->find_attribute_by_name($args{primaryKey})->get_read_method_ref; 
     my @args = ($args{primaryKey} => $this->$pk_accessor); 

पीएस। मैंने अभी देखा है कि यह वही तकनीक (मूस मेटा क्लास का उपयोग अपने नामकरण सम्मेलन को मानने के बजाय कोडेफ को देखने के लिए) भी भविष्यवाणी के लिए उपयोग नहीं किया जा सकता है, क्योंकि Class::MOP::Attribute में get_predicate_method_ref एक्सेसर नहीं है। :(

+0

मुझे नहीं लगता कि पर्ल के पार्स आदेश की वजह से संभव है:

## untested if (my $code = $object->can($hash{func})) { $object->$code(); } 

मैं प्रदर्शित करने के लिए एक बेकार, एक पंक्ति का उदाहरण दिया। आप $ हैश {func} को पहले स्केलर में कॉपी क्यों नहीं करना चाहते हैं? –

+0

इसे छोड़कर कोई विशेष कारण अनावश्यक लगता है, और यह एक दिलचस्प पहेली थी जो मुझे रोक देती थी। मुझे विश्वास नहीं था कि सिर्फ इसलिए कि मुझे जवाब नहीं पता था कि कोई जवाब नहीं था। :) (टीएल; डॉ संस्करण: क्योंकि मैं उत्सुक हूँ!) – Ether

+0

एर, ऐसा लगता है कि यदि आप मूस का उपयोग कर रहे हैं, तो आप अभी भी इसके बारे में गलत तरीके से जा रहे हैं। मूस की विशेषताओं में से एक मेटा ऑब्जेक्ट मॉडल है जिस पर यह बनाया गया है ... मुझे एक एहसास है कि एक विधि है जिसे आप स्ट्रिंग नाम से वास्तविक उप को देखने के लिए कॉल कर सकते हैं, जिसे आप कॉल कर सकते हैं, नंगे तारों का उपयोग करने के बजाय । मैं इसे अपने सिर के ऊपर से नहीं जानता, हालांकि ... –

उत्तर

14
Foo->${\$hash{func}}; 

लेकिन स्पष्टता के लिए की तरह कुछ का उपयोग कर सकते हैं, मैं शायद अभी भी लिखते हैं

my $method = $hash{func}; 
Foo->$method; 
+0

सरल * और * स्पष्ट; मुझे यह पसंद है! – Ether

+0

मैं पहले डॉलर के संकेत को समझता हूं। लेकिन मुझे जो मिलता है वह बैकस्लैश नहीं है। – innaM

+1

@ मनी: $ {...} को असंबद्धता के बजाए स्केलर अव्यवस्था के रूप में पार्स किया गया है क्योंकि सामग्री एक शाब्दिक स्ट्रिंग नहीं है। बैकस्लैश $ हैश {func} के मान का संदर्भ बनाना है। –

2

वहाँ एक कारण है कि आप सबरूटीन नाम भंडारण कर रहे हैं संदर्भ के बजाय कोड करने के लिए है?

जैसे

use strict; use warnings; 

package Foo; 
sub foo { print "in foo()\n" } 

package main; 
my %hash = (func => \&Foo::foo); 

$hash{func}->(); 

आप वर्ग के नाम से गुजर नहीं किया जाएगा, लेकिन है कि यदि आप के लिए महत्वपूर्ण है , आप

my %hash = (func => sub { return Foo->foo(@_) }); 
+0

हां, क्योंकि उपनाम मूस ऑब्जेक्ट्स से ली गई विशेषता के गुणों के अनुरूप हैं। – Ether

+0

मैंने अपना प्रश्न यह इंगित करने के लिए संपादित किया है कि 'Foo' या तो कक्षा का नाम या एक धन्य वस्तु हो सकता है। – Ether

+0

आप एक उप संदर्भ नहीं चाहते हैं क्योंकि यह विरासत तोड़ता है। –

1

आप की कोशिश की है UNIVERSAL's कर सकते हैं विधि: के रूप में? आप कुछ इस तरह लागू करने के लिए सक्षम होना चाहिए:

perl -MData::Dumper -le 'my %h = (f => "Dump"); my $o = Data::Dumper->new([qw/1 2 3/]); my $ref = $o->can($h{f}); print $o->$ref()' 
+0

हां, लेकिन फिर यह एक मूल नाम (जिसे रन्रिग उत्तर दिया गया है) के रूप में हैश मान का उपयोग करने के बारे में मेरे मूल प्रश्न से दूर एक मोड़ है। इस मामले में 'प्रश्न' एक प्रश्न संपादन में उल्लिखित एक से कम सही समाधान है, क्योंकि यह एक मूस रीडर के नामकरण के बारे में धारणा करता है। – Ether