2010-07-02 5 views
6

chromatic's recent blog मुझे मूस सबराउटिन has के बारे में उत्सुकता मिली। मैं मूस स्रोत कोड देख रहा था और देखा कि has सबराउटिन के अंदर, वैरिएबल @_ से अनपॅक किया गया है। $meta कहां से आता है? मैंने विभिन्न मूस और कक्षा :: एमओपी मॉड्यूल के माध्यम से wading शुरू कर दिया है। कई subroutines में, ऐसा लगता है कि $meta आमतौर पर @_ में पहला तर्क के रूप में पाया जाता है, भले ही इसे विशेष रूप से तर्क के रूप में पास नहीं किया गया हो।

संपादित करें:

sub has { 
    my $meta = shift; 
    my $name = shift; 

    Moose->throw_error('Usage: has \'name\' => (key => value, ...)') 
     if @_ % 2 == 1; 

    my %options = (definition_context => Moose::Util::_caller_info(), @_); 
    my $attrs = (ref($name) eq 'ARRAY') ? $name : [ ($name) ]; 
    $meta->add_attribute($_, %options) for @$attrs; 
} 

उत्तर

2

molecules टिप्पणी ysth answer में:

मुझे यकीन है कि कैसे सबरूटीन है इस बंद में परिवर्तित हो जाता नहीं कर रहा हूँ, लेकिन यह निश्चित रूप से पता चलता आयातित की curried प्रकृति

है यहाँ है (उम्मीद है!) यह कैसे एक आसान उदाहरण प्राप्त किया जा सकता है (हालांकि मुझे संदेह है कि Moose इसे अधिक जटिल और बेहतर तरीके से करता है!)

मुझे ta.pm

package Meta; 

sub new { 
    my $class = shift; 
    bless { @_ }, $class; 
} 

sub has { 
    my $meta = shift; 
    print "Given => @_ \n"; 
    print "meta $_ => ", $meta->{$_}, "\n" for keys %$meta; 
} 

1; 

Import.pm

package Import; 
use strict; 
use warnings; 
use Meta; 

# some arbitrary meta info! 
our $Meta = Meta->new(a => 'A', b => 'B'); 

sub import { 
    my $caller = caller; 

    # import 'has' into caller namespace 
    no strict 'refs'; 
    *{$caller . '::has'} = sub { $Meta->has(@_) }; 
} 

1; 

meta_has.pl

use strict; 
use warnings; 
use Import; 

has name => (is => 'rw', isa => 'Int'); 

अब अगर आप meta_has.pl चलाने आप मिल जाएगा:

# Given => name is rw isa Int 
# meta a => A 
# meta b => B 

आशा है कि मदद करता है।

/I3az/

+0

+1 महान उदाहरण। धन्यवाद। –

12

विशेष जादू आप देख रहे हैं Moose::Exporter में है: यहाँ has सबरूटीन के लिए मूल स्रोत कोड है। आप इस कोड से Moose.pm के माध्यम से has विधि मिलती है:

Moose::Exporter->setup_import_methods(
    with_meta => [ 
     qw(extends with has before after around override augment) 
    ], 
    as_is => [ 
     qw(super inner), 
     \&Carp::confess, 
     \&Scalar::Util::blessed, 
    ], 
); 

नोट setup_import_methods के लिए "with_meta" विकल्प - यह एक तरह से जो सुनिश्चित करता है कि पहला तर्क पारित कर दिया हो जाएगा में फोन करने वाले का नाम स्थान में उन तरीकों का आयात करता है मेटाक्लास ऑब्जेक्ट।

मूस का विस्तार करने वाले विभिन्न मूसएक्स मॉड्यूल कॉलर के नामस्थान में नए प्रतीकों को आयात करने के लिए मूस :: निर्यातक का उपयोग करते हैं। Moose::Cookbook::Extending::Recipe1 से शुरू होने पर, आप इस प्रक्रिया के बारे में और अधिक पढ़ें।

+0

+1 धन्यवाद। मैं देखता हूं कि मुझे वास्तव में इसे समझने से पहले मूस :: निर्यातक का अध्ययन करने में थोड़ा समय बिताना होगा। यह अभी भी मुझे स्पष्ट नहीं है कि '$ मेटा' (या अधिक सटीक रूप से, संदर्भ '$ मेटा' का संदर्भ बाद में संदर्भित होता है) '_ _' में आता है, लेकिन आपने निश्चित रूप से मुझे सही दिशा में इंगित किया है। –

+0

आप विशेष रूप से 'मूस ​​:: निर्यातक' के अंदर निजी विधि '_make_wrapped_sub_with_meta' देखना चाहते हैं। इस से वापसी मूल्य मूस द्वारा 'है' के रूप में स्थापित किया गया है। – perigrin

6

वास्तव में आपके पैकेज में आयात किया गया है नामित नहीं है() subroutine लेकिन एक बंद जो मेटा ऑब्जेक्ट को सम्मिलित करता है। आप देख सकते हैं वास्तव में यह कैसे के साथ होता है:

$ perl -we'use Data::Dump::Streamer; use Moose; Dump(\&has)' 
my ($extra,$sub,@ex_args); 
$extra = sub { 
     package Moose::Exporter; 
     use warnings; 
     use strict 'refs'; 
     Class::MOP::class_of(shift @_); 
    }; 
$sub = sub { 
    package Moose; 
    use warnings; 
    use strict 'refs'; 
    my $meta = shift @_; 
    my $name = shift @_; 
    'Moose'->throw_error(q[Usage: has 'name' => (key => value, ...)]) if @_ % 2 == 1; 
    my(%options) = ('definition_context', Moose::Util::_caller_info(), @_); 
    my $attrs = ref $name eq 'ARRAY' ? $name : [$name]; 
    $meta->add_attribute($_, %options) foreach (@$attrs); 
    }; 
@ex_args = ('main'); 
$CODE1 = sub { 
     package Moose::Exporter; 
     use warnings; 
     use strict 'refs'; 
     my(@curry) = &$extra(@ex_args); 
     return &$sub(@curry, @_); 
    }; 

$CODE1 बंद ही है; उपरोक्त संदर्भित चर हैं।

+0

मैंने इसे 'perl -we'package एक्स' में बदल दिया; डेटा :: डंप :: स्ट्रीमर का उपयोग करें; मूस का प्रयोग करें; डंप (\ & है) '' इसे मेरे डेबियन लेनी मशीन पर काम करने के लिए। –

+0

+1 धन्यवाद। मुझे यकीन नहीं है कि 'बंद' subroutine इस बंद करने में कैसे परिवर्तित हो जाता है, लेकिन यह निश्चित रूप से आयातित 'है' की करीबी प्रकृति को दिखाता है। –

+0

कोई भी जो आउटपुट देखना चाहता है जो थोड़ा कम गन्दा है, 'डंप (\ & है)' के साथ एक-लाइनर में 'डंप (\ & है)' को बदलने का प्रयास करें। –

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