alternate synopsis for named variants
[p5sagit/Package-Variant.git] / lib / Package / Variant.pm
index 8562b6b..091850f 100644 (file)
@@ -5,7 +5,7 @@ use Import::Into;
 use Module::Runtime qw(require_module);
 use Carp qw(croak);
 
-our $VERSION = '1.002000';
+our $VERSION = '1.002002';
 
 $VERSION = eval $VERSION;
 
@@ -94,9 +94,17 @@ sub import {
   };
 }
 
+sub build_variant_package_name {
+  my ($me, $variable, @args) = @_;
+  if ($variable->can('make_variant_package_name')) {
+    return $variable->make_variant_package_name(@args);
+  }
+  return "${variable}::_Variant_".++$Variable{$variable}{anon};
+}
+
 sub build_variant_of {
   my ($me, $variable, @args) = @_;
-  my $variant_name = "${variable}::_Variant_".++$Variable{$variable}{anon};
+  my $variant_name = $me->build_variant_package_name($variable, @args);
   foreach my $to_import (@{$Variable{$variable}{args}{importing}}) {
     my ($pkg, $args) = @$to_import;
     require_module $pkg;
@@ -127,6 +135,8 @@ Package::Variant - Parameterizable packages
 
 =head1 SYNOPSIS
 
+Creation of anonymous variants:
+
   # declaring a variable Moo role
   package My::VariableRole::ObjectAttr;
   use strictures 1;
@@ -160,6 +170,50 @@ Package::Variant - Parameterizable packages
   my $obj = My::Class::WithObjectAttr->new;
   $obj->some_obj; # returns a Some::Class instance
 
+And the same thing, only with named variants:
+
+  # declaring a variable Moo role that can be named
+  package My::VariableRole::ObjectAttrNamed;
+  use strictures 1;
+  use Package::Variant importing => ['Moo::Role'],
+    subs => [ qw(has around before after with) ];
+  use Module::Runtime 'module_notional_filename'; # only if you need protection
+
+  # this method is run at variant creation time to determine its custom
+  # package name. it can use the arguments or do something entirely else.
+  sub make_variant_package_name {
+    my ($class, $package, %arguments) = @_;
+    $package = "Private::$package"; # you can munge the input here if you like
+    # only if you *need* protection
+    die "Won't clobber $package" if $INC{module_notional_filename $package};
+    return $package;
+  }
+
+  # same as in the example above, except for the argument list. in this example
+  # $package is the user input, and
+  # $target_package is the actual package in which the variant gets installed
+  sub make_variant {
+    my ($class, $target_package, $package, %arguments) = @_;
+    my $name = $arguments{name};
+    has $name => (is => 'lazy');
+    install "_build_${name}" => sub {return $arguments{class}->new};
+  }
+
+  # using the role
+  package My::Class::WithObjectAttr;
+  use strictures 1;
+  use Moo;
+  use My::VariableRole::ObjectAttrNamed;
+
+  # create the role under a specific name
+  ObjectAttrNamed "My::Role" => (name => 'some_obj', class => 'Some::Class');
+  # and use it
+  with "Private::My::Role";
+
+  # using our class
+  my $obj = My::Class::WithObjectAttr->new;
+  $obj->some_obj; # returns a Some::Class instance
+
 =head1 DESCRIPTION
 
 This module allows you to build a variable package that contains a package
@@ -316,6 +370,19 @@ declared in L</subs> to customize the new variant package.
 This is a class method receiving the C<$target> package and the
 C<@arguments> defining the requested variant.
 
+=head2 make_variant_package_name
+
+  Some::Variant::Package->make_variant_package_name( @arguments );
+
+B<You may optionally provide this method.> If present, this method will be
+used to determine the package name for a particular variant being constructed.
+
+If you do not implement it, a unique package name something like
+
+  Some::Variant::Package::_Variant_A003
+
+will be created for you.
+
 =head2 import
 
   use Some::Variant::Package;