Changeset 11209

Show
Ignore:
Timestamp:
05/06/08 19:24:34 (5 years ago)
Author:
yappo
Message:

more Moosenize and add with method

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • lang/perl/Class-Component/trunk/lib/Class/Component/Component/Moosenize.pm

    r11127 r11209  
    77    $class->NEXT( import => %args ); 
    88 
     9    my $role_pkg   = "$class\::Role"; 
     10    # instasll import method to Plugin base class 
     11    no strict 'refs'; 
     12    *{"$role_pkg\::import"} = \&{"Class::Component::Component::Moosenize::Implement::inject_import"}; 
     13    unshift @{"$role_pkg\::ISA"}, 'Class::Component::Component::Moosenize::Role'; 
     14 
    915    my $plugin_pkg = "$class\::Plugin"; 
    10     # install Moose like methods to Plugin base class 
    11     Class::Component::Component::Moosenize::Implement::install_moose_methods($plugin_pkg); 
    1216    # install register method or wrapping to Plugin base class 
    1317    Class::Component::Component::Moosenize::Implement::install_register_method($plugin_pkg); 
    14  
    15     # instasll import method to Plugin base class 
    16     no strict 'refs'; 
    17     *{"$plugin_pkg\::import"} = \&{"Class::Component::Component::Moosenize::Implement::inject_import"}; 
    1818} 
    1919 
     
    2525 
    2626use Carp::Clan qw/Class::Component/; 
     27use Class::Inspector; 
    2728use UNIVERSAL::require; 
    2829 
    2930my $requires_map = {}; 
     31my $requires_with_map = {}; 
    3032 
    3133sub install_moose_methods { 
    3234    my $pkg = shift; 
    3335 
    34     for my $method (qw/ requires /) { 
     36    for my $method (qw/ requires with /) { 
    3537        no strict 'refs'; 
    3638        *{"$pkg\::$method"} = sub { unshift @_, $pkg; goto &$method }; 
     
    5254        }; 
    5355    } else { 
    54         eval "package $pkg; 
     56        my $code = "package $pkg; 
    5557            *register = sub { 
    5658                my \$class = shift; 
     
    6062            }; 
    6163        "; 
    62     } 
    63 } 
    64  
     64        eval $code;## no critic 
     65    } 
     66} 
     67 
     68# MyApp::Role->import 
    6569sub inject_import { 
    6670    my $class  = shift; 
     
    6973    # instasll Moose like methods to caller class 
    7074    install_moose_methods($caller); 
    71 } 
    72  
     75    $class->import_after($caller, @_); 
     76} 
     77 
     78# MyApp::Plugin->register 
    7379sub inject_register { 
    7480    check_requires(@_); 
     
    7985    my $self = shift; 
    8086    my $c    = shift; 
    81     my $kaller = ref $self || $self; 
    82     return if $moosenized_cache->{$kaller}++; 
     87    my $caller = ref $self || $self; 
     88    return if $moosenized_cache->{$caller}++; 
     89    return unless $requires_with_map->{$caller}; 
    8390 
    8491    my @error; 
    85     for my $class (@{ Class::Component::Implement->isa_list_cache($kaller) }) { 
    86         next if $kaller eq $class; 
    87         while (my($method, $attr) = each %{ $requires_map->{$class} }) { 
    88             my $code = $self->can($method); 
    89             push @error, sprintf("'%s' requires the method '%s' to be implemented by '%s'", $class, $method, $kaller) 
    90                 unless $code; 
    91  
    92             next unless $attr; 
    93  
    94             my $attribute = $attr; 
    95             if (ref $attr) { 
    96                 if (ref $attr eq 'HASH') { 
    97                     $attribute = delete $attr->{attribute}; 
    98                     $attr = $attr->{args}; 
     92    for my $class (reverse(@{ Class::Component::Implement->isa_list_cache($caller, $caller) }), $caller) { 
     93 
     94        my %class_requires; # not role class requires 
     95        if ($requires_map->{$class} && $caller ne $class) { 
     96            %class_requires = %{ $requires_map->{$class} }; 
     97        } else { 
     98            next unless $requires_with_map->{$class}; 
     99        } 
     100         
     101        for my $role (@{ $requires_with_map->{$class} }) { 
     102            next unless $requires_map->{$role}; 
     103            while (my($method, $attr) = each %{ $requires_map->{$role} }) { 
     104                if (my $msg = _check_requires($self, $c, $role, $caller, $method, $attr)) { 
     105                    push @error, $msg; 
    99106                } 
    100             } else { 
    101                 $attr = undef; 
    102107            } 
    103  
    104             my $attr_class; 
    105             if (($attr_class = $attribute) =~ s/^\+//) { 
    106                 $attr_class->require or croak $@; 
    107             } else { 
    108                 $attr_class = Class::Component::Implement->pkg_require($c => "Attribute::$attribute"); 
     108        } 
     109 
     110        while (my($method, $attr) = each %class_requires) { 
     111            if (my $msg = _check_requires($self, $c, $class, $caller, $method, $attr)) { 
     112                push @error, $msg; 
    109113            } 
    110  
    111             $attr_class->register($self, $c, $method, $attr, $code); 
    112114        } 
    113115    } 
    114116    @error and croak join("\n", @error); 
    115117} 
     118sub _check_requires { 
     119    my($self, $c, $caller, $role, $method, $attr) = @_; 
     120 
     121    my $code = $self->can($method); 
     122    unless ($code) { 
     123        return sprintf("'%s' requires the method '%s' to be implemented by '%s'", $role, $method, $caller); 
     124    } 
     125    return unless $attr; 
     126 
     127    # set attribute 
     128    my $attributes; 
     129    if (ref $attr eq 'HASH') { 
     130        $attributes = [ $attr ] 
     131    } elsif (ref $attr eq 'ARRAY') { 
     132        $attributes = $attr; 
     133    } else { 
     134        croak 'unimplimented refarence type'; 
     135    } 
     136 
     137    # fetch attribute class, value and go 
     138    for my $data (@{ $attributes }) { 
     139        my($attribute, $value); 
     140        if (ref $data eq 'HASH') { 
     141            ($attribute, $value) = each %{ $data }; 
     142        } else { 
     143            $attribute = $data; 
     144        } 
     145 
     146        my $attr_class; 
     147        if (($attr_class = $attribute) =~ s/^\+//) { 
     148            $attr_class->require or croak $@; 
     149        } else { 
     150            $attr_class = Class::Component::Implement->pkg_require($c => "Attribute::$attribute"); 
     151        } 
     152 
     153        $attr_class->register($self, $c, $method, $value, $code); 
     154    } 
     155 
     156    return; 
     157} 
     158 
    116159 
    117160# moose like methods 
     
    119162sub requires { 
    120163    my $caller = shift; 
    121     my %methods = @_ == 1 ? ( $_[0] => undef ) : @_; 
     164    my %methods = (@_ == 1) ? ( $_[0] => undef ) :  
     165                            ref $_[1] ? @_ : 
     166                                      map { $_ => undef } @_; 
    122167    my $kaller = ref $caller || $caller; 
    123168    $requires_map->{$kaller} ||= {}; 
     
    128173} 
    129174 
     175sub with { 
     176    my $caller = shift; 
     177    my $role   = shift; 
     178 
     179    $role->require or croak $@; 
     180    my %has_methods = map { $_ => 1 } @{ Class::Inspector->functions($caller) }; 
     181    for my $method (@{ Class::Inspector->functions($role) }) { 
     182        next if $has_methods{$method}; 
     183        no strict 'refs'; 
     184        *{"$caller\::$method"} = *{"$role\::$method"}; 
     185    } 
     186    $requires_with_map->{$caller} ||= []; 
     187    push @{ $requires_with_map->{$caller} }, $role; 
     188} 
     189 
    130190sub before { 
    131191} 
     
    134194} 
    135195 
     196use Data::Dumper; 
     197 
     198package # hide pause 
     199    Class::Component::Component::Moosenize::Role; 
     200use strict; 
     201use warnings; 
     202use Carp::Clan qw/Class::Component/; 
     203 
     204sub import_after {} 
    1362051; 
    137206 
     
    147216=head1 EXPORT METHODS 
    148217 
    149 =ovar 4 
    150  
    151 =item requires 
     218=over 4 
     219 
     220=item requires, with 
    152221 
    153222  package MyApp; 
     
    157226  package MyApp::Plugin; 
    158227  use base 'Class::Component::Plugin'; 
     228  use MyApp::Role; 
    159229  requires 'foo'; 
    160   requires bar => 'Method', baz => '+Foo::MyAttribute'; 
    161   requires hop => { attribute => 'Method', args => 'jump' }; 
     230  requires bar => ['Method'], baz => ['+Foo::MyAttribute']; 
     231  requires hop => +{ Method => 'jump' }; 
     232 
     233  package MyApp::Role; 
    162234 
    163235  package MyApp::Role::Blah; 
    164   use MyApp::Plugin; 
     236  use MyApp::Role; 
    165237  requires 'blah'; 
    166238 
    167239  package MyApp::Plugin::Hoge; 
    168   use MyApp::Plugin; 
    169   use base qw( MyApp::Plugin MyApp::Role::Blah ); 
     240  use base qw( MyApp::Plugin  ); 
     241  use MyApp::Role; 
     242  with 'MyApp::Role::Blah'; 
    170243 
    171244  sub foo { # simple method