+ my $step = shift;
+
+ my $hash_form = $self->run_hook('hash_form', $step) || {};
+ my $hash_base = $self->run_hook('hash_base', $step) || {};
+ my $hash_comm = $self->run_hook('hash_common', $step) || {};
+ my $hash_fill = $self->run_hook('hash_fill', $step) || {};
+ my $hash_swap = $self->run_hook('hash_swap', $step) || {};
+ my $hash_errs = $self->run_hook('hash_errors', $step) || {};
+
+ $hash_errs->{$_} = $self->format_error($hash_errs->{$_}) foreach keys %$hash_errs;
+ $hash_errs->{'has_errors'} = 1 if scalar keys %$hash_errs;
+
+ my $fill = {%$hash_form, %$hash_base, %$hash_comm, %$hash_fill};
+ my $swap = {%$hash_form, %$hash_base, %$hash_comm, %$hash_swap, %$hash_errs};
+
+ $self->run_hook('print', $step, $swap, $fill);
+}
+
+sub print {
+ my ($self, $step, $swap, $fill) = @_;
+ my $file = $self->run_hook('file_print', $step); # get a filename relative to template_path
+ my $out = $self->run_hook('swap_template', $step, $file, $swap);
+ $self->run_hook('fill_template', $step, \$out, $fill);
+ $self->run_hook('print_out', $step, \$out);
+}
+
+sub handle_error {
+ my ($self, $err) = @_;
+
+ die $err if $self->{'_handling_error'};
+ local $self->{'_handling_error'} = 1;
+ local $self->{'_recurse'} = 0; # allow for this next step - even if we hit a recurse error
+
+ $self->stash->{'error_step'} = $self->current_step;
+ $self->stash->{'error'} = $err;
+ $self->replace_path($self->error_step);
+
+ eval { $self->jump };
+ die $@ if $@ && $@ ne "Long Jump\n";
+}
+
+###---------------------###
+# read only accessors
+
+sub allow_morph { $_[0]->{'allow_morph'} }
+sub allow_nested_morph { $_[0]->{'allow_nested_morph'} }
+sub auth_args { $_[0]->{'auth_args'} }
+sub charset { $_[0]->{'charset'} || '' }
+sub conf_args { $_[0]->{'conf_args'} }
+sub conf_die_on_fail { $_[0]->{'conf_die_on_fail'} || ! defined $_[0]->{'conf_die_on_fail'} }
+sub conf_path { $_[0]->{'conf_path'} || $_[0]->base_dir_abs }
+sub conf_validation { $_[0]->{'conf_validation'} }
+sub default_step { $_[0]->{'default_step'} || 'main' }
+sub error_step { $_[0]->{'error_step'} || '__error' }
+sub fill_args { $_[0]->{'fill_args'} }
+sub forbidden_step { $_[0]->{'forbidden_step'} || '__forbidden' }
+sub form_name { $_[0]->{'form_name'} || 'theform' }
+sub history { $_[0]->{'history'} ||= [] }
+sub js_step { $_[0]->{'js_step'} || 'js' }
+sub login_step { $_[0]->{'login_step'} || '__login' }
+sub mimetype { $_[0]->{'mimetype'} || 'text/html' }
+sub path_info { $_[0]->{'path_info'} || $ENV{'PATH_INFO'} || '' }
+sub path_info_map_base { $_[0]->{'path_info_map_base'} ||[[qr{/(\w+)}, $_[0]->step_key]] }
+sub recurse_limit { $_[0]->{'recurse_limit'} || 15 }
+sub script_name { $_[0]->{'script_name'} || $ENV{'SCRIPT_NAME'} || $0 }
+sub stash { $_[0]->{'stash'} ||= {} }
+sub step_key { $_[0]->{'step_key'} || 'step' }
+sub template_args { $_[0]->{'template_args'} }
+sub template_path { $_[0]->{'template_path'} || $_[0]->base_dir_abs }
+sub val_args { $_[0]->{'val_args'} }
+sub val_path { $_[0]->{'val_path'} || $_[0]->template_path }
+
+sub conf_obj {
+ my $self = shift;
+ return $self->{'conf_obj'} || do {
+ my $args = $self->conf_args || {};
+ $args->{'paths'} ||= $self->conf_path;
+ $args->{'directive'} ||= 'MERGE';
+ require CGI::Ex::Conf;
+ CGI::Ex::Conf->new($args);
+ };
+}
+
+sub template_obj {
+ my ($self, $args) = @_;
+ return $self->{'template_obj'} || do {
+ require Template::Alloy;
+ Template::Alloy->new($args);
+ };
+}
+
+sub auth_obj {
+ my ($self, $args) = @_;
+ return $self->{'auth_obj'} || do {
+ require CGI::Ex::Auth;
+ CGI::Ex::Auth->new($args);
+ };