Re: [Catalyst] RFC: Catalyst::Plugin::AutoValidate

2008-04-10 Thread Matt S Trout
On Wed, Apr 09, 2008 at 11:06:04AM +0200, Markus Holzer wrote:
> Hello fellows, please bear with me, as this is my first contribution to 
> Catalyst.
> 
> From the pod: This Plugin validates request parameters against a 
> specification in a file that directly relates to the requests path (like 
> the .fb files when using Formbuilder).
> 
> I'm curiuos of your opinions.

Should be a controller base class.

Using a plugin for this is bad style - see for example Controller::FormBuilder
which replaces the old Plugin::FormBuilder

-- 
  Matt S Trout   Need help with your Catalyst or DBIx::Class project?
   Technical Directorhttp://www.shadowcat.co.uk/catalyst/
 Shadowcat Systems Ltd.  Want a managed development or deployment platform?
http://chainsawblues.vox.com/http://www.shadowcat.co.uk/servers/

___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


Re: [Catalyst] RFC: Catalyst::Plugin::AutoValidate

2008-04-09 Thread Kieren Diment


On 9 Apr 2008, at 20:07, Markus Holzer wrote:

Moritz Onken schrieb:
But is it really a plugin? I'd prefer to use it as a controller  
base class because it is controller specific. This way you could  
chose which controllers should use this plugin and let the others  
do their work without being disturbed by this plugin (and you  
could still use it in the Root controller).
Yes, it is a plugin. A key feature is to be able to specify a  
"paranoid mode" in which no action will be run if there is no  
parameter spec for it.


Also you can still use it Controller-wise. If you omit the code in  
the "begin : Private" action, the plugin will silently do it's  
validation and place it's results
in  $c->request->{validated}and $c->request->{validation_error} (if  
any). You can ask for them frim within the controller and act  
accordingly.


But for me, the main point of this beast is that i can drop a  
formal parameter definition next to a controller/action without  
cluttering the controller code.
(as formbuilder does and following the catalyst credo "dont repeat  
yourself" =)




What, you mean like Catalyst::Controller::Formbuilder?  If so,  
emulate its example. The FB plugin is deprecated.



___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


Re: [Catalyst] RFC: Catalyst::Plugin::AutoValidate

2008-04-09 Thread Markus Holzer

Moritz Onken schrieb:
But is it really a plugin? I'd prefer to use it as a controller base 
class because it is controller specific. This way you could chose 
which controllers should use this plugin and let the others do their 
work without being disturbed by this plugin (and you could still use 
it in the Root controller).
Yes, it is a plugin. A key feature is to be able to specify a "paranoid 
mode" in which no action will be run if there is no parameter spec for it.


Also you can still use it Controller-wise. If you omit the code in the 
"begin : Private" action, the plugin will silently do it's validation 
and place it's results
in  $c->request->{validated}and $c->request->{validation_error} (if 
any). You can ask for them frim within the controller and act accordingly.


But for me, the main point of this beast is that i can drop a formal 
parameter definition next to a controller/action without cluttering the 
controller code.
(as formbuilder does and following the catalyst credo "dont repeat 
yourself" =)


I'm still thinking about how to add a kind of polymorphism to this.


___
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/


Re: [Catalyst] RFC: Catalyst::Plugin::AutoValidate

2008-04-09 Thread Moritz Onken

Hi Markus,

great plugin. But is it really a plugin? I'd prefer to use it as a  
controller base class because it is controller specific. This way you  
could chose which controllers should use this plugin and let the  
others do their work without being disturbed by this plugin (and you  
could still use it in the Root controller).


I think the C::Plugin namespace is already poisened enough :)


just my 2 cents,

Cheers

moritz

Am 09.04.2008 um 11:06 schrieb Markus Holzer:
Hello fellows, please bear with me, as this is my first contribution  
to Catalyst.


From the pod: This Plugin validates request parameters against a  
specification in a file that directly relates to the requests path  
(like the .fb files when using Formbuilder).


I'm curiuos of your opinions.

Thank you,
Holli

___


package Catalyst::Plugin::AutoValidate;

use warnings;
use strict;

use YAML qw( LoadFile );

use Catalyst::Request;
use Config::Validate;
use Data::Dumper;
use NEXT;

our $VERSION = 0.01;

sub prepare {
  my $class = shift;
  my $c = $class->NEXT::prepare( @_ );
my ( $config, $rpath, $spec_root, $spec_file, $validation_spec,  
$validator );

# config for this package
  $config= $c->config->{'Catalyst::Plugin::AutoValidate'};
  # the request path
  $rpath = $c->request->path || $config->{index_spec} || 'index';
  # root dir to look for specifications
  $spec_root = $config->{spec_root} || "$c->{home}/cvspec";
  # spec file, deduced from path
  $spec_file = "$spec_root/${rpath}.".($config- 
>{spec_extension}||"cvs");

# check if there are custom types configured
  if ( $config->{types} )
  {
  # add to the validation module
  if ( ref( $config->{types} ) eq "ARRAY" )
  {
  for ( @{$config->{types}} )
  {
  Config::Validate::add_default_type(%$_);
  }
  }
  else
  {
  Config::Validate->add_default_type(%{$config->{types}});
  }
# move the types, so they won't get reprocessed another  
time

  $config->{xtypes} = delete $config->{types};
  }
# there is no matching spec file
  unless ( -e $spec_file )
  {
  # that's ok or not, depending if we are paranoid
  $c->request->{validated} = $config->{paranoid} ? 0 : 1;
  }
  else
  {
  # load spec and validate the request against it
  $validation_spec = LoadFile( $spec_file );
  $validator   = Config::Validate->new( schema =>  
$validation_spec );

# will die if validation fails
  eval { $validator->validate( config => $c->request- 
>{parameters} ) };


  unless ( $@ )
  {
  $c->request->{validated} = 1;
  }
  else
  {
  $_ = "$@"; s/^.+?validate\(\): //; s/instead.+//;
  $c->request->{validation_error} = "$_";
  $c->request->{validated} = 0;
  }
  }
return $c;
}
1;

__DATA__
=head1 NAME

Catalyst::Plugin::AutoValidate - Catalyst-Plugin for easy automatic  
validation of Request-Parameters


=head1 VERSION

Version 0.01

=head1 SYNOPSIS

This Plugin validates request parameters against a specification in  
a file that directly
relates to the requests path (like the .fb files when using  
Formbuilder).


For the "heavy lifting" it uses L;
All validation options from that module are supported, as they get  
simply passed through.


# application code
package MyApp;
use strict;
use warnings;

use Catalyst qw(AutoValidate);

# MyApp::Controller::Root.pm
# check parameters and display error message when
# appropriate. Does NOT RUN THE CONTROLLER in that case,
# otherwise proceed with controller
sub begin : Private
{
   my ($self, $c) = @_;

   $c->response->body( $c->request->{validation_error} ),
   $c->detach
   unless $c->request->{validated};
}
# $c->{home}/cvspec/math/multiply.cvs (YAML)
a:
   type: integer
b:
   type: integer
# MyApp::Controller::Math.pm
sub multiply : Local
{
   my ($self, $c) = @_;
   # this is safe because Autovalidate ensures both are integers
   $s->stash->{result} = $c->req->param('a') / $c->req->param('a')
}


=head1 CONFIGURATION

__PACKAGE__->config(
'Catalyst::Plugin::AutoValidate' =>
{
   # root dir for looking up specifications
   spec_root => '',
  # when set, all requests without specification die
   paranoid  => 0,
  # the name of the index spec (for empty paths)
   index_spec => 'index',

   # extension for spec-files
   spec_extension => 'cvs',
  # custom types
   types =>
   [
   # generator sub that generates a closure, could come in handy  
for lookups

   {
   name => 'custom',
   validate => sub {
   my $lookup = { exists => 1 };
   return sub { die "Not in lookup table!" unless  
$lookup->{$_[1]} };

   }->()
   },
   # or easier
   sub { die "Doesnt match!" unless $_[1] =~ /[abc]/ };
   ]
}
);

=cut


=head1 AUTHOR

[Catalyst] RFC: Catalyst::Plugin::AutoValidate

2008-04-09 Thread Markus Holzer
Hello fellows, please bear with me, as this is my first contribution to 
Catalyst.


From the pod: This Plugin validates request parameters against a 
specification in a file that directly relates to the requests path (like 
the .fb files when using Formbuilder).


I'm curiuos of your opinions.

Thank you,
Holli

___


package Catalyst::Plugin::AutoValidate;

use warnings;
use strict;

use YAML qw( LoadFile );

use Catalyst::Request;
use Config::Validate;
use Data::Dumper;
use NEXT;

our $VERSION = 0.01;

sub prepare {
   my $class = shift;
   my $c = $class->NEXT::prepare( @_ );
  
   my ( $config, $rpath, $spec_root, $spec_file, $validation_spec, 
$validator );
  
   # config for this package

   $config= $c->config->{'Catalyst::Plugin::AutoValidate'};
   # the request path
   $rpath = $c->request->path || $config->{index_spec} || 'index';
   # root dir to look for specifications
   $spec_root = $config->{spec_root} || "$c->{home}/cvspec";
   # spec file, deduced from path
   $spec_file = "$spec_root/${rpath}.".($config->{spec_extension}||"cvs");
  
   # check if there are custom types configured

   if ( $config->{types} )
   {
   # add to the validation module
   if ( ref( $config->{types} ) eq "ARRAY" )
   {
   for ( @{$config->{types}} )
   {
   Config::Validate::add_default_type(%$_);
   }
   }
   else
   {
   Config::Validate->add_default_type(%{$config->{types}});
   }
  
   # move the types, so they won't get reprocessed another time

   $config->{xtypes} = delete $config->{types};
   }
  
   # there is no matching spec file

   unless ( -e $spec_file )
   {
   # that's ok or not, depending if we are paranoid
   $c->request->{validated} = $config->{paranoid} ? 0 : 1;
   }
   else
   {
   # load spec and validate the request against it
   $validation_spec = LoadFile( $spec_file );
   $validator   = Config::Validate->new( schema => 
$validation_spec );
  
   # will die if validation fails
   eval { $validator->validate( config => $c->request->{parameters} 
) };


   unless ( $@ )
   {
   $c->request->{validated} = 1;
   }
   else
   {
   $_ = "$@"; s/^.+?validate\(\): //; s/instead.+//;
   $c->request->{validation_error} = "$_";
   $c->request->{validated} = 0;
   }
   }
  
   return $c;

}
1;

__DATA__
=head1 NAME

Catalyst::Plugin::AutoValidate - Catalyst-Plugin for easy automatic 
validation of Request-Parameters


=head1 VERSION

Version 0.01

=head1 SYNOPSIS

This Plugin validates request parameters against a specification in a 
file that directly

relates to the requests path (like the .fb files when using Formbuilder).

For the "heavy lifting" it uses 
L;
All validation options from that module are supported, as they get 
simply passed through.


# application code
package MyApp;
use strict;
use warnings;

use Catalyst qw(AutoValidate);

# MyApp::Controller::Root.pm
# check parameters and display error message when
# appropriate. Does NOT RUN THE CONTROLLER in that case,
# otherwise proceed with controller
sub begin : Private
{
my ($self, $c) = @_;

$c->response->body( $c->request->{validation_error} ),
$c->detach
unless $c->request->{validated};
}

# $c->{home}/cvspec/math/multiply.cvs (YAML)
a:
type: integer
b:
type: integer

# MyApp::Controller::Math.pm
sub multiply : Local
{
my ($self, $c) = @_;
# this is safe because Autovalidate ensures both are integers
$s->stash->{result} = $c->req->param('a') / $c->req->param('a')
}


=head1 CONFIGURATION

__PACKAGE__->config(
'Catalyst::Plugin::AutoValidate' =>
{
# root dir for looking up specifications
spec_root => '',
   
# when set, all requests without specification die

paranoid  => 0,
   
# the name of the index spec (for empty paths)

index_spec => 'index',

# extension for spec-files
spec_extension => 'cvs',
   
# custom types

types =>
[
# generator sub that generates a closure, could come in handy 
for lookups

{
name => 'custom',
validate => sub {
my $lookup = { exists => 1 };
return sub { die "Not in lookup table!" unless 
$lookup->{$_[1]} };

}->()
},
# or easier
sub { die "Doesnt match!" unless $_[1] =~ /[abc]/ };
]
}
);

=cut


=head1 AUTHOR

Markus Holzer, C<<  >>

=head1 BUGS

Please report any bugs or feature requests to 
C, or through
the web interface at 
L.  
I will be notified, and then you'll

automatically be notified of progress on your bug as I make changes.




=head1 SUPPORT

You can find documentation for this module with the perldoc command.