Changeset 32282

Show
Ignore:
Timestamp:
04/12/09 04:10:41 (4 years ago)
Author:
ktat
Message:

support Sub::Exporter
support some of exporting ways from Sub::Exporter.
refactor code.

Location:
lang/perl/Util-Any/trunk
Files:
11 added
7 modified

Legend:

Unmodified
Added
Removed
  • lang/perl/Util-Any/trunk/Changes

    r31439 r32282  
    11Revision history for Util-Any 
     2 
     30.07    2009/04/12 03:58 
     4        support Sub::Exporter 
     5        support some of exporting ways from Sub::Exporter 
    26 
    370.06    2009/03/22 14:55 
  • lang/perl/Util-Any/trunk/MANIFEST

    r31439 r32282  
    1313t/01-util-kind-hash.t 
    1414t/01-util-kind-debug.t 
     15t/01-util-kind-my-coron.t 
     16t/01-util-kind-my-minus.t 
    1517t/01-util-kind-my.t 
     18t/01-util-kind-my-minus.t 
     19t/01-util-kind-my-coron.t 
    1620t/02-util-func-scalar.t 
    1721t/01-util-kind-all.t 
     
    3842t/09-exporter2.t 
    3943t/09-exporter-no-args.t 
     44t/10-sub-exporter.t 
     45t/10-sub-exporter2.t 
     46t/10-sub-exporter-no-args.t 
     47t/11-sub-exporter-all.t 
     48t/11-sub-exporter-full-all.t 
     49t/12-sub-exporter-like-export.t 
    4050t/lib/MyUtil.pm 
    4151t/lib/MyUtilBase.pm 
     
    4454t/lib/UtilExporter.pm 
    4555t/lib/UtilExporterSimple.pm 
     56t/lib/UtilSubExporter.pm 
     57t/lib/UtilSubExporter2.pm 
     58t/lib/exampleHello.pm 
  • lang/perl/Util-Any/trunk/lib/Util/Any.pm

    r31439 r32282  
    44use Carp (); 
    55use warnings; 
    6 use List::MoreUtils qw/uniq/; 
     6use List::MoreUtils qw/uniq any/; 
    77use strict; 
    88 
     
    1515             }; 
    1616 
     17our $SubExporterImport = 'do_import'; 
     18 
    1719sub import { 
    18   my $pkg = shift; 
    19   my $caller = (caller)[0]; 
    20  
    21   return $pkg->_base_import($caller, @_) if @_ and $_[0] =~/^-\w+$/; 
    22  
     20  my ($pkg, $caller) = (shift, (caller)[0]); 
     21  return $pkg->_base_import($caller, @_) if @_ and $_[0] =~/^-[A-Z]\w+$/; 
     22 
     23  my %opt = (prefix => 0, module_prefix => 0, debug => 0); 
     24  if (@_ > 1 and ref $_[-1] eq 'HASH') { 
     25    @opt{qw/prefix module_prefix debug/} = (delete @{$_[-1]}{qw/prefix module_prefix debug/}); 
     26    pop @_ unless %{$_[-1]}; 
     27  } 
     28 
     29  my $config = do { no strict 'refs'; ${$pkg . '::Utils'} }; 
     30  my ($arg, $want) = $pkg->_arrange_args(\@_, $config, $caller); 
     31  foreach my $kind (keys %$want) { 
     32    my ($prefix, $module_prefix, $options) = ('', '', []); 
     33    Carp::croak "$pkg doesn't have such kind of functions : $kind" unless exists $config->{$kind}; 
     34    my ($funcs, $local_definition, $kind_prefix) = $pkg->_func_definitions($kind, $want->{$kind}); 
     35 
     36    foreach my $class (@{$config->{$kind}}) { # $class is class name or array ref 
     37      my @funcs = @{$funcs->{$kind} || []}; 
     38      ($class, $module_prefix, $options) = ref $class ? @$class : ($class, '', []); 
     39      $prefix = $kind_prefix                             ? $kind_prefix   : 
     40                ($opt{module_prefix} and $module_prefix) ? $module_prefix : 
     41                $opt{prefix}                             ? lc($kind) . '_': ''; 
     42 
     43      my $evalerror = ''; 
     44      if ($evalerror = do { local $@; eval "require $class"; $evalerror = $@ }) { 
     45        $opt{debug} == 2 ? Carp::croak $evalerror : Carp::carp $evalerror; 
     46      } 
     47      my %rename; 
     48      if (ref $options eq 'HASH') { 
     49        push @funcs, @{$options->{-select}} if exists $options->{-select}; 
     50        if (exists $options->{-except}) { 
     51          Carp::croak "cannot use -select & -except in same time." if exists $options->{select}; 
     52          my %except; 
     53          @except{@{$options->{-except}}} = (); 
     54          push @funcs, grep !exists $except{$_}, @{_all_funcs_in_class($class)}; 
     55        } elsif (! @funcs) { 
     56          @funcs =  @{_all_funcs_in_class($class)}; 
     57        } 
     58        foreach my $o (grep !/^-/, keys %$options) { 
     59          if (defined &{$class . '::' . $o}) { 
     60            push @funcs , $o; 
     61            $rename{$o} = $options->{$o}; 
     62          } 
     63        } 
     64      } elsif(ref $options eq 'ARRAY') { 
     65        push @funcs, @$options; 
     66      } 
     67      $pkg->_do_export($caller, $class, \@funcs, $local_definition, \%rename, $prefix); 
     68  } 
     69} 
     70 
     71sub _all_funcs_in_class { 
     72  my ($class) = @_; 
     73  my %f; 
    2374  no strict 'refs'; 
    24  
    25   my $config = ${$pkg . '::Utils'}; 
    26   my %want; 
    27   my %opt = (prefix => 0, module_prefix => 0, debug => 0); 
    28  
    29   if (@_ > 1 and ref $_[-1] eq 'HASH') { 
    30     %opt = (%opt, %{pop()}); 
    31   } 
    32  
    33   if (@_) { 
    34     if (ref $_[0] eq 'HASH') { 
    35       my %_want = %{shift()}; 
    36       %want = map {lc($_) => $_want{$_}} keys %_want; 
    37     } elsif (lc($_[0]) eq 'all') { 
    38       @want{keys %$config} = (); 
    39     } else { 
    40       @want{map lc $_, @_} = (); 
    41     } 
    42   } 
    43  
    44   foreach my $kind (keys %$config) { 
    45     my ($prefix, $module_prefix, $options) = ('', '', []); 
    46  
    47     if (exists $want{$kind}) { 
    48       foreach my $class (@{$config->{$kind}}) { 
    49         ($class, $module_prefix, $options) = ref $class ? @$class : ($class, '', []); 
    50         if ($opt{module_prefix} and $module_prefix) { 
    51           $prefix = $module_prefix; 
    52         } elsif ($opt{prefix}) { 
    53           $prefix = lc($kind) . '_'; 
    54         } 
    55         my $evalerror; 
    56         { 
    57           local $@; 
    58           eval "require $class"; 
    59           $evalerror = $@; 
    60         }; 
    61         unless ($evalerror) { 
    62           my $export_funcs = ref $options eq 'ARRAY' ? $options : $options->{-select}; 
    63           my (%funcs, %rename); 
    64           no strict 'refs'; 
    65           @funcs{@{$class . '::EXPORT_OK'}, @{$class . '::EXPORT'}} = (); 
    66           my @funcs = grep defined &{$class . '::' . $_}, keys %funcs; 
    67           if (my $want_func = $want{$kind}) { 
    68             my %w; 
    69             @w{@$want_func} = (); 
    70             @funcs = grep exists $w{$_}, @funcs; 
    71           } elsif (@{$export_funcs || []}) { 
    72             @funcs = grep defined &{$class . '::' . $_}, @$export_funcs; 
    73           } 
    74           if (ref $options eq 'HASH') { 
    75             if (exists $options->{-except}) { 
    76               Carp::croak "cannot use -select & -except in same time." if @{$export_funcs || []}; 
    77               my %except; 
    78               @except{@{$options->{-except}}} = (); 
    79               @funcs = grep !exists $except{$_}, @funcs; 
    80             } 
    81             foreach my $o (grep !/^-/, keys %$options) { 
    82               if (defined &{$class . '::' . $o}) { 
    83                 push @funcs , $o; 
    84                 $rename{$o} = $options->{$o}; 
    85               } 
    86             } 
    87           } 
    88           ExportTo::export_to($caller => ($prefix or %rename) 
    89                               ? {map {$prefix . ($rename{$_} || $_) => $class . '::' . $_} uniq @funcs} 
    90                               : [map $class . '::' . $_, uniq @funcs]); 
    91         } elsif(defined $opt{debug}) { 
    92           $opt{debug} == 2 ? Carp::croak $evalerror : Carp::carp $evalerror; 
     75  @f{@{$class . '::EXPORT_OK'}, @{$class . '::EXPORT'}} = (); 
     76  return [grep defined &{$class . '::' . $_}, keys %f]; 
     77} 
     78 
     79sub _do_export { 
     80  my ($pkg, $caller, $class, $funcs, $local_definition, $rename, $prefix) = @_; 
     81  my @export_funcs = @$funcs ? @$funcs : @{_all_funcs_in_class($class)}; 
     82  if (%$local_definition) { 
     83    foreach my $func (keys %$local_definition) { 
     84        foreach my $def (@{$local_definition->{$func}}) { 
     85          my $local_rename = delete $def->{-as} || ''; 
     86          ExportTo::export_to 
     87              ($caller => 
     88               { 
     89                ($local_rename ? $local_rename : $prefix ? $prefix . $func : $func) 
     90                  => %$def ? sub { no strict 'refs'; &{$class . '::' . $func}(%$def, @_) } 
     91                         : $class . '::' . $func 
     92               }); 
    9393        } 
    9494      } 
     95      @export_funcs = grep !exists $local_definition->{$_}, @export_funcs; 
    9596    } 
    96   } 
    97   my $import_module = $pkg->_use_import_module; 
    98   if ($import_module) { 
     97    ExportTo::export_to($caller => ($prefix or %$rename) 
     98                        ? {map {($prefix . ($rename->{$_} || $_)) => $class . '::' . $_} @export_funcs} 
     99                        : [map $class . '::' . $_, uniq @export_funcs]); 
     100  } 
     101} 
     102 
     103sub _insert_want_arg { 
     104  my ($config, $f, $setting, $want, $arg) = @_; 
     105  my $lf = lc $f; 
     106  exists $config->{$lf} ? 
     107    $want->{$lf} = $setting : 
     108    push @$arg, $f, defined $setting ? $setting : (); 
     109} 
     110 
     111sub _arrange_args { 
     112  my ($pkg, $org_args, $config, $caller) = @_; 
     113  my (@arg, %want); 
     114  my $import_module = $pkg->_use_import_module || ''; 
     115  if (@$org_args) { 
     116    @$org_args = %{$org_args->[0]} if ref $org_args->[0] eq 'HASH'; 
     117 
     118    if (lc($org_args->[0]) eq 'all') { 
     119      # import all functions which Util::Any proxy 
     120      @want{keys %$config} = (); 
     121    } elsif (lc($org_args->[0]) =~ /^[:-]all$/) { 
     122      # import ALL functions 
     123      @want{keys %$config} = (); 
     124      if ($import_module) { 
     125        if ($import_module eq 'Expoter'          or 
     126            $import_module eq 'Exporter::Simple' 
     127           ) { 
     128          no strict 'refs'; 
     129          no warnings; 
     130          push @arg, ':all' if ${$pkg . '::EXPORT_TAGS'}{":all"}; 
     131        } elsif ($import_module eq 'Sub::Exporter') { 
     132          push @arg, '-all'; 
     133        } elsif ($import_module eq 'Perl6::Exporter::Attrs') { 
     134          push @arg, ':ALL'; 
     135        } 
     136      } 
     137    } elsif (any {ref $_} @$org_args) { 
     138      for (my $i = 0; $i < @$org_args; $i++) { 
     139        my $f = $org_args->[$i]; 
     140        my $setting = $org_args->[$i + 1] ? $org_args->[++$i] : undef; 
     141        _insert_want_arg($config, $f, $setting, \%want, \@arg); 
     142      } 
     143    } else { 
     144      # export specified kinds 
     145      foreach my $f (@$org_args) { 
     146        _insert_want_arg($config, $f, undef, \%want, \@arg); 
     147      } 
     148    } 
     149  } 
     150  $pkg->_do_base_import($import_module, $caller, \@arg) if (@arg or !@$org_args) and $import_module; 
     151  return \@arg, \%want; 
     152} 
     153 
     154sub _func_definitions { 
     155  my ($pkg, $kind, $want_func_definition, $kind_prefix) = @_; 
     156  my (%funcs, %local_definition); 
     157  if (ref $want_func_definition eq 'HASH') { 
     158    # list => {func => {-as => 'rename'}};  list => {-prefix => 'hoge_' } 
     159    $kind_prefix = $want_func_definition->{-prefix} 
     160      if exists $want_func_definition->{-prefix}; 
     161    foreach my $f (grep !/^-/, keys %$want_func_definition) { 
     162      push @{$funcs{$kind} ||= []}, $f; 
     163      $local_definition{$f} = [$want_func_definition->{$f}]; 
     164    } 
     165  } elsif (ref $want_func_definition eq 'ARRAY') { 
     166    foreach (my $i = 0; $i < @$want_func_definition; $i++) { 
     167      my ($k, $v) = @{$want_func_definition}[$i, $i + 1]; 
     168      if (ref $v) { 
     169        $i++; 
     170        if ($k eq '-prefix') { 
     171          $kind_prefix = $v; 
     172        } else { 
     173          push @{$funcs{$kind} ||= []}, $k; 
     174          push @{$local_definition{$k} ||= []}, $v; 
     175        } 
     176      } else { 
     177        push @{$funcs{$kind} ||= []}, $k; 
     178      } 
     179    } 
     180    @{$funcs{$kind} ||= []} = uniq @{$funcs{$kind} ||= []}; 
     181  } 
     182  return \%funcs, \%local_definition, $kind_prefix || ''; 
     183} 
     184 
     185sub _do_base_import { 
     186  # working with other modules like Expoter 
     187  my ($pkg, $import_module, $caller, $arg) = @_; 
     188  my $pkg_utils; 
     189  { 
    99190    no strict 'refs'; 
    100191    no warnings; 
    101     my $pkg_utils = ${$pkg . '::Utils'}; 
    102     my @arg = defined $pkg_utils ? (grep !exists $pkg_utils->{$_}, @_) 
    103                                  : (grep !exists $Utils->{$_}, @_); 
    104     if ((@_ and @arg) or !@_) { 
    105       if ($import_module eq 'Perl6::Export::Attrs') { 
    106         eval "package $caller; $pkg" . '->Perl6::Export::Attrs::_generic_import(@arg);'; 
    107       } elsif ($import_module eq 'Exporter::Simple') { 
    108         eval "package $caller; $pkg" . '->Exporter::Simple::import(@arg);'; 
    109       } elsif ($import_module eq 'Exporter') { 
    110         eval "package $caller; $pkg" . '->Exporter::import(@arg);'; 
    111       } 
    112     } 
    113   } 
     192    $pkg_utils = ${$pkg . '::Utils'}; 
     193  } 
     194  if ($import_module eq 'Perl6::Export::Attrs') { 
     195    eval "package $caller; $pkg" . '->Perl6::Export::Attrs::_generic_import(@$arg);'; 
     196  } elsif ($import_module eq 'Exporter::Simple') { 
     197    eval "package $caller; $pkg" . '->Exporter::Simple::import(@$arg);'; 
     198  } elsif ($import_module eq 'Exporter') { 
     199    eval "package $caller; $pkg" . '->Exporter::import(@$arg);'; 
     200  } elsif ($import_module eq 'Sub::Exporter') { 
     201    no strict 'refs'; 
     202    no warnings; 
     203    my $import_name =  ${"${pkg}::SubExporterImport"} || $Util::Any::SubExporterImport; 
     204    eval "package $caller; $pkg" . '->$import_name(@$arg);'; 
     205  } 
     206  die $@ if $@; 
    114207} 
    115208 
     
    128221      *{$caller . '::MODIFY_CODE_ATTRIBUTES'} = \&Perl6::Export::Attrs::_generic_MCA; 
    129222      *{$caller . '::_use_import_module'} = sub { 'Perl6::Export::Attrs' }; 
     223    } elsif ($flg eq '-subexporter') { 
     224      eval "use Sub::Exporter ();"; 
     225      *{$caller . '::_use_import_module'} = sub { 'Sub::Exporter' }; 
    130226    } elsif ($flg eq '-exportersimple') { 
    131227      eval "use Exporter::Simple ();"; 
     
    152248=cut 
    153249 
    154 our $VERSION = '0.06'; 
     250our $VERSION = '0.07'; 
    155251 
    156252=head1 SYNOPSIS 
     
    185281    use Util::Any qw/all/, {prefix => 1}; 
    186282    use Util::Any qw/list/, {prefix => 1}; 
    187     use Util::Any {List => qw/uniq/}, {prefix => 1}; 
     283    use Util::Any {list => ['uniq']}, {prefix => 1}; 
    188284     
    189285    print list_uniq qw/1, 0, 1, 2, 3, 3/; 
     
    400496 NG $Utils = { LIST => [qw/List::Util/]}; 
    401497 OK $Utils = { list => [qw/List::Util/]}; 
     498 OK $Utils = { -list => [qw/List::Util/]}; 
     499 OK $Utils = { ':list' => [qw/List::Util/]}; 
    402500 
    403501=head3 C<all> cannot be used for key. 
     
    470568=head2 RENAME FUNCTIONS 
    471569 
    472 To rename function name. Using this option with -select or -exception, 
     570To rename function name, use this option with -select or -exception, 
    473571this definition is prior to them. 
    474572 
     
    489587  }; 
    490588 
     589=head2 EXPORTING LIKE Sub::Exporter 
     590 
     591It's experimental featrue. not enough tested. and only support '-prefix', '-as' and pass default args. 
     592 
     593 use UtilSubExporter list => {-prefix => 'list__', min => {-as => "list___min"}}, 
     594                     # The following is normal Sub::Exporter importing 
     595                     -greet => {-prefix => "greet_"}, 
     596                     'askme' => {-as => "ask_me"}; 
     597 
     598Check t/lib/UtilSubExporter.pm, t/10-sub-exporter-like-epxort.t and  t/12-sub-exporter-like-export.t 
     599 
    491600 
    492601=head1 WORKING WITH EXPORTER-LIKE MODULES 
    493602 
    494603CPAN has some modules to export functions. 
    495 Util::Any can work with some of such modules, L<Exporter>, L<Exporter::Simple> and L<Perl6::Export::Attrs>. 
     604Util::Any can work with some of such modules, L<Exporter>, L<Exporter::Simple>, L<Sub::Exporter> and L<Perl6::Export::Attrs>. 
    496605If you want to use other modules, please inform me or implement import method by yourself. 
    497606 
     
    502611Normaly, you use; 
    503612 
     613 package YourUtils; 
     614  
    504615 use Util::Any -Base; # or "use base qw/Util::Any/;" 
    505616 
     
    511622 # if you want to use Exporter::Simple 
    512623 use Util::Any -ExporterSimple; 
     624 # if you want to use Sub::Exporter 
     625 use Util::Any -SubExporter; 
    513626 # if you want to use Perl6::Export::Attrs 
    514627 use Util::Any -Perl6ExportAttrs; 
    515628 
    516629That's all. 
    517 Note that don't use base the above modules in your utility module. 
     630Note that B<don't use base the above modules in your utility module>. 
     631 
     632There is one notice to use Sub::Exporter. 
     633 
     634 Sub::Exporter::setup_exporter 
     635       ({ 
     636           as => 'do_import', # name is important 
     637           exports => [...], 
     638           groups  => { ... }, 
     639       }); 
     640 
     641You must pass "as" option to setup_exporter and its value must be "do_import". 
     642If you want to change this name, do the following. 
     643 
     644 Sub::Exporter::setup_exporter 
     645       ({ 
     646           as => $YourUtils::SubExporterImport = '__do_import', 
     647           exports => [...], 
     648           groups  => { ... }, 
     649       }); 
    518650 
    519651=head3 EXAMPLE to USE Perl6::Export::Attrs in YOUR OWN UTIL MODULE 
     652 
     653Perl6::Export::Attributes is not recommended in the following URL 
     654(http://www.perlfoundation.org/perl5/index.cgi?pbp_module_recommendation_commentary). 
     655So, you'd beter use other exporter module. It is left as an example. 
    520656 
    521657 package Util::Yours; 
     
    537673 
    538674=head2 IMPLEMENT IMPORT by YOURSELF 
     675 
     676Perl6::Export::Attributes is not recommended in the following URL 
     677(http://www.perlfoundation.org/perl5/index.cgi?pbp_module_recommendation_commentary). 
     678So, you'd beter use other exporter module. It is left as an example. 
    539679 
    540680You can write your own import method and BEGIN block like the following. 
     
    624764patches and collaborators are welcome. 
    625765 
     766=head1 SEE ALSO 
     767 
     768The following modules can work with Util::Any. 
     769 
     770L<Exporter>, L<Exporter::Simple>, L<Sub::Exporter> and L<Perl6::Export::Attrs>. 
     771 
    626772=head1 ACKNOWLEDGEMENTS 
    627773 
  • lang/perl/Util-Any/trunk/t/02-util-func-scalar-prefix.t

    r25939 r32282  
    44no strict 'refs'; 
    55 
    6 ok(defined &scalar_weaken , 'weaken'); 
    7 ok(defined &scalar_blessed , 'blessed'); 
     6ok(defined &scalar_weaken , 'scalar_weaken'); 
     7ok(defined &scalar_blessed , 'scalar_blessed'); 
    88my $hoge = bless {}; 
    99ok(scalar_blessed $hoge, "blessed test"); 
    1010 
    1111foreach (grep {$_ ne 'weaken' and $_ ne 'blessed'} @Scalar::Util::EXPORT_OK) { 
    12   ok(! defined &{'scalar_' . $_} , $_); 
     12  ok(! defined &{'scalar_' . $_} , 'not defined ' . $_); 
    1313} 
    1414 
    1515foreach (@Hash::Util::EXPORT_OK) { 
    1616  no strict 'refs'; 
    17   ok(! defined &{$_} , $_) if defined &{'Hash::Util::' . $_}; 
     17  ok(! defined &{$_} , 'not defined ' . $_) if defined &{'Hash::Util::' . $_}; 
    1818} 
    1919 
    2020foreach (@List::Util::EXPORT_OK) { 
    21   ok(! defined &{'list_' . $_} , $_); 
     21  ok(! defined &{'list_' . $_} , 'not defined ' . $_); 
    2222} 
    2323 
    2424foreach (@List::MoreUtils::EXPORT_OK) { 
    25   ok(! defined &{'list_' . $_} , $_); 
     25  ok(! defined &{'list_' . $_} , 'not defined ' . $_); 
    2626} 
  • lang/perl/Util-Any/trunk/t/04-option-select.t

    r26846 r32282  
    2828ok(defined &lmin, 'defined min as lmin but not in select'); 
    2929ok(defined &shuffle, 'not defined shuffle'); 
    30 ok(!defined &min, 'defined min'); 
    31 ok(!defined &minstr, 'defined minstr'); 
     30ok(!defined &min,    'not defined min'); 
     31ok(!defined &minstr, 'not defined minstr'); 
    3232ok(!defined &reduce, 'not defined reduce'); 
    3333 
  • lang/perl/Util-Any/trunk/t/lib/MyUtil.pm

    r25939 r32282  
    44our $Utils = 
    55  { 
    6    list => [['List::Util' => 'lu_']], 
    7    error => ['Ktat::Ktat::Ktat'], 
     6   list    => [['List::Util' => 'lu_']], 
     7   -list   => [['List::Util' => 'lu_']], 
     8   ':list' => [['List::Util' => 'lu_']], 
     9   error   => ['Ktat::Ktat::Ktat'], 
    810  }; 
    911 
  • lang/perl/Util-Any/trunk/t/lib/UtilExporter.pm

    r31439 r32282  
    99our @EXPORT_OK = qw/askme hello hi/; 
    1010our %EXPORT_TAGS = ( 
    11                     'greet' => [qw/hello hi/], 
    12                     'uk'    => [qw/hello/], 
    13                     'us'    => [qw/hi/], 
    14                    ); 
     11                    'greet' => [qw/hello hi/], 
     12                    'uk'    => [qw/hello/], 
     13                    'us'    => [qw/hi/], 
     14                    'hello' => [qw/hello_name hello_where/], 
     15                   ); 
    1516 
    1617our $Utils = clone $Util::Any::Utils; 
     
    1819                 ['List::Util', '', [qw(first min minstr max maxstr sum)]], 
    1920                ]; 
     21$Utils->{-hello} = ['exampleHello']; 
    2022 
    2123sub hello { "hello there" }