Acme-Sort-Sleep

 view release on metacpan or  search on metacpan

local/lib/perl5/Struct/Dumb.pm  view on Meta::CPAN

         }
         if( my ( $extrakey ) = keys %values ) {
            croak "usage: $pkg does not recognise '$extrakey'";
         }
         bless \@values, $pkg;
      };
   }
   else {
      my $fieldcount = @$fields;
      my $argnames = join ", ", map "\$$_", @$fields;
      $constructor = sub {
         @_ == $fieldcount or croak "usage: $pkg($argnames)";
         bless [ @_ ], $pkg;
      };
   }

   no strict 'refs';
   *{"${pkg}::$_"} = $subs{$_} for keys %subs;
   *{"${caller}::$name"} = $constructor;

   if( my $predicate = $opts{predicate} ) {
      *{"${caller}::$predicate"} = sub { ( ref($_[0]) || "" ) eq $pkg };
   }

   *{"${pkg}::_forbid_arrayification"} = sub {
      return if !HAVE_OVERLOADING and caller eq __PACKAGE__;
      croak "Cannot use $pkg as an ARRAY reference"
   };

   require overload;
   $pkg->overload::OVERLOAD(
      '@{}'  => sub { $_[0]->_forbid_arrayification; return $_[0] },
      '0+'   => sub { refaddr $_[0] },
      '""'   => sub { sprintf "%s=Struct::Dumb(%#x)", $pkg, refaddr $_[0] },
      'bool' => sub { 1 },
      fallback => 1,
   );
}

=head2 struct

   struct $name => [ @fieldnames ],
      named_constructor => (1|0),
      predicate         => "is_$name";

Creates a new structure type. This exports a new function of the type's name
into the caller's namespace. Invoking this function returns a new instance of
a type that implements those field names, as accessors and mutators for the
fields.

Takes the following options:

=over 4

=item named_constructor => BOOL

Determines whether the structure will take positional or named arguments.

=item predicate => STR

If defined, gives the name of a second function to export to the caller's
namespace. This function will be a type test predicate; that is, a function
that takes a single argmuent, and returns true if-and-only-if that argument is
an instance of this structure type.

=back

=cut

=head2 readonly_struct

   readonly_struct $name => [ @fieldnames ],
      ...

Similar to L</struct>, but instances of this type are immutable once
constructed. The field accessor methods will not be marked with the
C<:lvalue> attribute.

Takes the same options as L</struct>.

=cut

=head1 NOTES

=head2 Allowing ARRAY dereference

The way that forbidding access to instances as if they were ARRAY references
is currently implemented uses an internal method on the generated structure
class called C<_forbid_arrayification>. If special circumstances require that
this exception mechanism be bypassed, the method can be overloaded with an
empty C<sub {}> body, allowing the struct instances in that class to be
accessed like normal ARRAY references. For good practice this should be
limited by a C<local> override.

For example, L<Devel::Cycle> needs to access the instances as plain ARRAY
references so it can walk the data structure looking for reference cycles.

 use Devel::Cycle;

 {
    no warnings 'redefine';
    local *Point::_forbid_arrayification = sub {};

    memory_cycle_ok( $point );
 }

=head1 TODO

=over 4

=item *

Consider adding an C<coerce_hash> option, giving name of another function to
convert structs to key/value pairs, or a HASH ref.

=back

=head1 AUTHOR

Paul Evans <leonerd@leonerd.org.uk>



( run in 1.121 second using v1.01-cache-2.11-cpan-39bf76dae61 )