Rethinkdb

 view release on metacpan or  search on metacpan

lib/Rethinkdb/Base.pm  view on Meta::CPAN

package Rethinkdb::Base;

use strict;
use warnings;
use utf8;
use feature ();

# No imports because we get subclassed, a lot!
use Carp ();

# Only Perl 5.14+ requires it on demand
use IO::Handle ();

sub import {
  my $class = shift;
  return unless my $flag = shift;
  no strict 'refs';

  # Base
  if ( $flag eq '-base' ) { $flag = $class }

  # Strict
  elsif ( $flag eq '-strict' ) { $flag = undef }

  # Module
  else {
    my $file = $flag;
    $file =~ s/::|'/\//g;
    require "$file.pm" unless $flag->can('new');
  }

  # ISA
  if ($flag) {
    my $caller = caller;
    push @{"${caller}::ISA"}, $flag;
    *{"${caller}::has"} = sub { attr( $caller, @_ ) };
  }

  # Mojo modules are strict!
  strict->import;
  warnings->import;
  utf8->import;
  feature->import(':5.10');
}

sub new {
  my $class = shift;
  bless @_ ? @_ > 1 ? {@_} : { %{ $_[0] } } : {}, ref $class || $class;
}

# Performance is very important for something as often used as accessors,
# so we optimize them by compiling our own code, don't be scared, we have
# tests for every single case
sub attr {
  my ( $class, $attrs, $default ) = @_;
  return unless ( $class = ref $class || $class ) && $attrs;

  Carp::croak 'Default has to be a code reference or constant value'
    if ref $default && ref $default ne 'CODE';

  # Compile attributes
  for my $attr ( @{ ref $attrs eq 'ARRAY' ? $attrs : [$attrs] } ) {
    Carp::croak qq{Attribute "$attr" invalid} unless $attr =~ /^[a-zA-Z_]\w*$/;

    # Header (check arguments)
    my $code = "package $class;\nsub $attr {\n  if (\@_ == 1) {\n";

    # No default value (return value)
    unless ( defined $default ) { $code .= "    return \$_[0]{'$attr'};" }

    # Default value
    else {

      # Return value
      $code .= "    return \$_[0]{'$attr'} if exists \$_[0]{'$attr'};\n";

      # Return default value
      $code .= "    return \$_[0]{'$attr'} = ";
      $code .= ref $default eq 'CODE' ? '$default->($_[0]);' : '$default;';
    }

    # Store value
    $code .= "\n  }\n  \$_[0]{'$attr'} = \$_[1];\n";

    # Footer (return invocant)
    $code .= "  \$_[0];\n}";

    # We compile custom attribute code for speed
    no strict 'refs';
    warn "-- Attribute $attr in $class\n$code\n\n" if $ENV{RDB_BASE_DEBUG};
    Carp::croak "Rethinkdb::Base error: $@" unless eval "$code;1";
  }
}

sub tap {
  my ( $self, $cb ) = @_;
  $_->$cb for $self;
  return $self;
}



( run in 2.351 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )