]> git.vpit.fr Git - perl/modules/Lexical-Types.git/blobdiff - lib/Lexical/Types.pm
This is 0.04
[perl/modules/Lexical-Types.git] / lib / Lexical / Types.pm
index f84372b17fda02d9ac87d0b327fcd91d8a4c7481..e935d3880a124e6b1ce213f2a6b4575f78d37b7e 100644 (file)
@@ -13,33 +13,63 @@ Lexical::Types - Extend the semantics of typed lexicals.
 
 =head1 VERSION
 
-Version 0.02
+Version 0.04
 
 =cut
 
 our $VERSION;
 BEGIN {
- $VERSION = '0.02';
+ $VERSION = '0.04';
 }
 
 =head1 SYNOPSIS
 
+    { package Str; }
+
+    {
+     package My::Types::Str;
+
+     sub new { bless { }, shift }
+    }
+
+    use Lexical::Types as => sub { 'My::Types::' . $_[0] => 'new' };
+
+    my Str $x; # $x is now a My::Types::Str object
+
     {
-     package Str;
+     package My::Types::Int;
 
-     sub TYPEDSCALAR { Some::String::Implementation->new }
+     sub TYPEDSCALAR { bless { }, shift }
     }
 
     use Lexical::Types;
 
-    my Str $x; # $x is now a Some::String::Implementation object
+    use constant Int => 'My::Types::Int';
+
+    my Int $y; # $y is now a My::Types::Int object
 
 =head1 DESCRIPTION
 
-This pragma allows you to hook the execution of typed lexicals declarations (C<my Str $x>).
-In particular, it can be used to automatically tie or bless typed lexicals.
+This pragma allows you to hook the execution of typed lexicals declarations (C<my Str $x>) by calling a configurable method in a configurable package at each run.
+In particular, it can be used to automatically tie or bless typed lexicals whenever they are initialized.
+
+Remind that for C<perl> to be able to parse C<my Str $x>, you need :
+
+=over 4
+
+=item *
+
+either the C<Str> package to be defined ;
+
+=item *
 
-It is B<not> implemented with a source filter.
+or for C<Str> to be a constant sub returning a valid defined package.
+
+=back
+
+so make sure you follow one of those two strategies to define your types.
+
+This pragma is B<not> implemented with a source filter.
 
 =cut
 
@@ -82,9 +112,9 @@ If the value given is a code reference C<$mangler>, it will be called at compile
 
 either an empty list, in which case the current typed lexical definition will be skipped (thus it won't be altered to trigger a run-time hook) ;
 
-    use Lexical::Types as => sub { return $_[0] =~ /Str/ ? () : @_ };
-    my Str $x; # nothing special
-    my Int $y; # calls Int->TYPEDSCALAR
+    use Lexical::Types as => sub { return $_[0] =~ /Str/ ? @_ : () };
+    my Str $y; # calls Str->TYPEDSCALAR
+    my Int $x; # nothing special
 
 =item *
 
@@ -95,10 +125,15 @@ or the desired package and method name, in that order (if any of those is C<unde
 
 =back
 
-=back
+Note that if the type is a constant, C<$_[0]> will be set to the I<value> of constant and not to its name.
 
-The initializer method receives an alias to the pad entry of C<$x> in C<$_[1]> and the original type name (C<Str>) in C<$_[2]>.
-You can either edit C<$_[1]> in place, in which case you should return an empty list, or return a new scalar that will be copied into C<$x>.
+    use Lexical::Types as => sub { $_[0] => 'new' };
+    use constant Str => 'MyStr';
+    my Str $x; # calls MyStr->new
+
+This means in particular that you can't both use constant types and redirect several types to different methods of the same package, because then you can't distinguish between the original types with C<$_[0]>.
+
+=back
 
 =cut
 
@@ -140,6 +175,22 @@ sub unimport {
  $^H{+(__PACKAGE__)} = undef;
 }
 
+=head1 RUN-TIME INITIALIZER METHOD
+
+The initializer method receives an alias to the pad slot of the initialized lexical in C<$_[1]> and the original type name in C<$_[2]>.
+You can either edit C<$_[1]> in place, in which case you should return an empty list, or return a new scalar that will be copied into the pad slot.
+
+    use Lexical::Types as => 'My';
+
+    my Str $x;
+
+    ...
+
+    sub My::Str::TYPEDSCALAR {
+     # $_[1] is an alias to $x, and $_[2] is 'Str'
+     ...
+    }
+
 =head1 INTEGRATION
 
 You can integrate L<Lexical::Types> in your module so that using it will provide types to your users without asking them to load either L<Lexical::Types> or the type classes manually.
@@ -163,6 +214,37 @@ You can integrate L<Lexical::Types> in your module so that using it will provide
 
     sub new_int { ... }
 
+If you prefer to use constants rather than creating empty packages, you can replace the previous example with something like this :
+
+    package MyTypes;
+
+    BEGIN { require Lexical::Types; }
+
+    sub import {
+     my $pkg = caller;
+     for (qw/Str Int/) {
+      my $type = __PACKAGE__ . '::' . $_;
+      no strict 'refs';
+      no warnings 'redefine';
+      *{$pkg.'::'.$_} = eval "sub () { '$type' }";
+     }
+     Lexical::Types->import(
+      as => sub { $_[0] => 'new' }
+     );
+    }
+
+    sub unimport {
+     Lexical::Types->unimport;
+    }
+
+    package MyTypes::Str;
+
+    sub new { ... }
+
+    package MyTypes::Int;
+
+    sub new { ... }
+
 =head1 CAVEATS
 
 For C<perl> to be able to parse C<my Str $x>, you need :
@@ -179,7 +261,7 @@ or for C<Str> to be a constant sub returning a valid defined package.
 
 =back
 
-Those restrictions apply even if you use the C<'as'> option to redirect to another package, and are unlikely to find a workaround as this happens deep inside the lexer - far from the reach of an extension.
+The restrictions on the type (being either a defined package name or a constant) apply even if you use the C<'as'> option to redirect to another package, and are unlikely to find a workaround as this happens deep inside the lexer - far from the reach of an extension.
 
 Only one mangler or prefix can be in use at the same time in a given scope.