Sub-Starter

 view release on metacpan or  search on metacpan

lib/Sub/Starter.pm  view on Meta::CPAN

  }elsif( $var =~ $RE_scalar_ref ){
    $name = $1; # . '_sref';
    $attr{-type} = 'scalar_ref';
    $attr{-variable} = '$' . $name;
  }elsif( $var =~ $RE_array_ref ){
    $name = $1; # . '_aref';
    $attr{-type} = 'array_ref';
    $attr{-variable} = '$' . $name;
  }elsif( $var =~ $RE_hash_ref ){
    $name = $1; # . '_href';
    $attr{-type} = 'hash_ref';
    $attr{-variable} = '$' . $name;
  }elsif( $var =~ $RE_code_ref ){
    $name = $1; # . '_cref';
    $attr{-type} = 'code_ref';
    $attr{-variable} = '$' . $name;
  }elsif( $var =~ $RE_typeglob ){
    $name = $1; # . '_gref';
    $attr{-type} = 'typeglob';
    $attr{-variable} = '$' . $name;
  }else{
    croak "unknown variable type: $var";
  }

  my $length = length( $name ) + 1;
  $parsed->{-max_variable} = $length if $parsed->{-max_variable} < $length;
  return %attr;
}

# --------------------------------------
#       Name: _parse_returns
#      Usage: _parse_returns( $parsed, $returns_part );
#    Purpose: Parse the sub's return variables
# Parameters:       $parsed -- storage hash
#             $returns_part -- part of the usage statement before the assignment
#    Returns: none
#
sub _parse_returns {
  my $parsed  = shift @_;
  my $returns = shift @_;
  my $list_var = 0;
  my %seen = ();

  return unless length $returns;

  if( $returns =~ s{ \+\= \z }{}msx ){
    $parsed->{-assignment} = 0;
  }else{
    $returns =~ s{ \= \z }{}msx;
  }

  if( $returns =~ m{ \A ( ([^\|]*) \| )? \( (.*?) \) \z }msx ){
    $parsed->{-returns_alternate} = $2;
    my $list = $3;

    if( $parsed->{-returns_alternate} ){
      $parsed->{-returns_alternate} = { _parse_variable( $parsed, $parsed->{-returns_alternate} ) };
      croak "alternative return variable is not a scalar" if $parsed->{-returns_alternate}{-type} ne 'scalar';
    }

    for my $var ( split m{ \, }msx, $list ){
      if( $seen{$var} ++ ){
        croak "Return parameter $var repeated";
      }
      my %attr = _parse_variable( $parsed, $var );
      push @{ $parsed->{-returns} }, { %attr };
      if( $attr{-type} eq 'array' or $attr{-type} eq 'hash' ){
        croak "array or hash may only occur at end of returns list" if $list_var ++;
      }
    }
  }elsif( $returns =~ m{ \A ([^\|]*) \| (.*?) \z }msx ){
    $parsed->{-returns_alternate} = $1;
    my $var = $2;

    $parsed->{-returns_alternate} = { _parse_variable( $parsed, $parsed->{-returns_alternate} ) };
    croak "alternative return variable is not a scalar" if $parsed->{-returns_alternate}{-type} ne 'scalar';
    if( $seen{$var} ++ ){
      croak "Return parameter $var repeated";
    }
    my %attr = _parse_variable( $parsed, $var );
    push @{ $parsed->{-returns} }, { %attr };
  }else{
    if( $seen{$returns} ++ ){
      croak "Return parameter $returns repeated";
    }
    my %attr = _parse_variable( $parsed, $returns );
    push @{ $parsed->{-returns} }, { %attr };
  }
  return;
}

# --------------------------------------
#       Name: _parse_parameters
#      Usage: _parse_parameters( $parsed, $param_part );
#    Purpose: Break the parameters into variables and store them.
# Parameters:     $parsed -- storage hash
#             $param_part -- part of the usage statement including optional parameters
#    Returns: none
#
sub _parse_parameters {
  my $parsed     = shift @_;
  my $param_part = shift @_;
  my $opt_params = '';
  my $list_var = 0;
  my %seen = ();

  if( $param_part =~ m{ \A ([^;]*) \; (.*) }msx ){
    $param_part = $1;
    $opt_params = $2;
  }

  for my $param ( split m{ \, }msx, $param_part ){
    if( $seen{$param} ++ ){
      die "Parameter $param repeated\n";
    }
    my %attr = _parse_variable( $parsed, $param );
    push @{ $parsed->{-parameters} }, { %attr };
    if( $attr{-type} eq 'array' or $attr{-type} eq 'hash' ){
      die "array or hash may only occur at end of parameter list" if $list_var ++;
    }
  }

  for my $param ( split m{ \, }msx, $opt_params ){
    if( $seen{$param} ++ ){
      die "Parameter $param repeated\n";
    }
    my %attr = _parse_variable( $parsed, $param );
    push @{ $parsed->{-parameters} }, { optional=>1, %attr };
    if( $attr{-type} eq 'array' or $attr{-type} eq 'hash' ){
      die "array or hash may only occur at end of parameter list" if $list_var ++;
    }
  }

  return;
}

# --------------------------------------
#       Name: parse_usage
#      Usage: $sub_starter->parse_usage( $usage_statement );
#    Purpose: Parse a usage statement and store its contents.
# Parameters: $usage_statement -- See POD for details
#    Returns: none
#
sub parse_usage {
  my $self            = shift @_;
  my $usage_statement = shift @_;
  my $usage = $usage_statement;

  # create a scratch pad
  my $parsed = dclone( \%Default_attributes );

  # clean up for easier processing
  $usage =~ s{ \s+ }{}gmsx;
  $usage =~ s{ \)? \;? \z }{}msx;

  # find returns via an assignment symbol
  my $returns_part = '';
  my $func_part = $usage;
  if( $usage =~ m{ \A ( [^=]* \= ) (.*) }msx ){
    $returns_part = $1;
    $func_part = $2;
  }
  if( $func_part =~ m{ = }msx ){
    croak "Multiple assignments in usage statement";
  }

  # get the name and possible object
  my $name_part = $func_part;
  my $param_part = '';
  if( $name_part =~ m{ \A ( [^()]* ) \( ( .*? ) \)? \z }msx ){
    $name_part = $1;
    $param_part = $2;
  }
  if( $name_part =~ s{ \A (.*?) \-\> }{}msx ){
    $parsed->{-object} =  $1;
    $parsed->{-max_variable} = 5;
  }
  $name_part =~ s{ \A \& }{}msx;
  $parsed->{-name} = $name_part;

  # parse the rest
  _parse_returns( $parsed, $returns_part );
  _parse_parameters( $parsed, $param_part );

lib/Sub/Starter.pm  view on Meta::CPAN

      $value = '@_';
    }
    if( $format =~ m{ \* }msx ){
      push @$text, sprintf( $format, $self->{-max_variable}, $item->{-variable}, $value );
    }else{
      push @$text, sprintf( $format, $item->{-variable}, $value );
    }
  }

  # do returns
  @list = ();
  if( $self->{-returns_alternate} ){
    push @list, $self->{-returns_alternate};
  }
  push @list, @{ $self->{-returns} };

  # print 'returns @list ', Dumper \@list;
  for my $item ( @list ){
    next if $seen{$item->{-variable}} ++;
    my $value = $self->{-assignment};
    if( $item->{-type} eq 'scalar' ){
      # value already set
    }elsif( $item->{-type} eq 'array' || $item->{-type} eq 'hash' ){
      $value = '()';
    }elsif( $item->{-type} eq 'array_ref' ){
      $value = '[]';
    }elsif( $item->{-type} eq 'hash_ref' ){
      $value = '{}';
    }else{
      $value = 'undef';
    }
    if( $format =~ m{ \* }msx ){
      push @$text, sprintf( $format, $self->{-max_variable}, $item->{-variable}, $value );
    }else{
      push @$text, sprintf( $format, $item->{-variable}, $value );
    }
  }

  return $text;
}

# --------------------------------------
#       Name: fill_out
#      Usage: $text = $sub_starter->fill_out( \@template );
#    Purpose: Fill out the template with the current parameters
# Parameters: \@template -- List of lines with replacements
#    Returns:      $text -- resulting text
#
sub fill_out {
  my $self     = shift @_;
  my $template = shift @_;
  my $text     = '';

  for my $template_line ( @$template ){
    my $line = $template_line;  # copy to modify

    if( $line =~ m{ \A (.*?) \e\[1m \( ([^\)]*) \) \e\[0?m (.*) }msx ){
      my $front = $1;
      my $item = $2;
      my $back = $3;
      my ( $directive, @arguments ) = split m{ \s+ }msx, $item;

      my $expansion; # array reference
      if( exists $Expand{$directive} ){
        $expansion = &{ $Expand{$directive} }( $self, @arguments );
      }else{
        carp "no expansion for '$directive'";
        next;
      }

      for my $expanded ( @$expansion ){
        $text .= $front . $expanded . $back;
      }

    }else{
      $text .= $line;
    }
  }

  return $text;
}

1;
__DATA__
__END__

=head1 NAME

Sub::Starter - Creates a skeletal framework for Perl sub's.

=head1 VERSION

This document refers to Sub::Starter version v1.0.6

=head1 SYNOPSIS

  use Sub::Starter;

=head1 DESCRIPTION

This module is for providing a simple and consist way of
creating sub's.  It provides methods for loading the
interface to a sub and, using a template, output its
skeleton.  This skeleton can then be populate with code.

=head2 Usage Statements

A usage statement shows how a sub will be used.  It is used
by the C<parse_usage()> method.  It is not valid Perl.  It
uses the make-a-reference-to notation for references.  This
is to give a clear indication of what the references is to.

The following variables can be used for the parameters,
including the optional ones, and the returns;

=over 4

=item $scalar -- a scalar variable

=item @array -- an array variable or list



( run in 1.995 second using v1.01-cache-2.11-cpan-71847e10f99 )