[jifty-devel] jifty dispatcher problem

Ruslan Zakirov ruz at bestpractical.com
Mon Dec 15 04:52:15 EST 2008


Hello,

Robin, I've added you to Cc as I think Want module with some
improvements might help. More details at the bottom.

Here is simplest case that fails:

under x => run {
    on some => run { show('some_template') }
};

This thing doesn't work in the right way. some_template is rendered
even if requested path is /x/anything_else_but_not_some. Here is what
happening. Here what we have:

    if ($Dispatcher) {
        # We are under an operation -- carry the rule forward
        foreach my $rule ( [ $op => splice( @_, 0, length($proto) ) ], @_ ) {
            $Dispatcher->_handle_rule($rule);
        }
    } elsif (wantarray) {
        ( [ $op => splice( @_, 0, length($proto) ) ], @_ );
    } elsif ( defined wantarray ) {
        [ [ $op => splice( @_, 0, length($proto) ) ], @_ ];
    } else {
        _push_rule($pkg, [ $op => splice( @_, 0, length($proto) ) ] );
    }

When first run block is executed, we're in dispatcher already so all
rules are applied as soon as function is called. What cause the
problem "on" function has ($$@) prototype and perl calls "run" next to
it first to collect arguments for "on". The following change fixes
this particular issue, but rises another one:

    if (wantarray) {
        ( [ $op => splice( @_, 0, length($proto) ) ], @_ );
    } elsif ( defined wantarray ) {
        [ [ $op => splice( @_, 0, length($proto) ) ], @_ ];
    } elsif ($Dispatcher) {
        # We are under an operation -- carry the rule forward
        foreach my $rule ( [ $op => splice( @_, 0, length($proto) ) ], @_ ) {
            $Dispatcher->_handle_rule($rule);
        }
    } else {
        _push_rule($pkg, [ $op => splice( @_, 0, length($proto) ) ] );
    }

However, after this we must call a rule in void context all the time
we want to actually execute the rule, for example:

sub model {
    my $class = find(shift);
    return $mclass if $mclass;

    abort(404);
}

Pretty innocent function however it's always called in array or scalar
context and tailcall to abort gets messed about what to do - execute
or return intermediate representation. With proposed change model
function will return something instead of aborting request. what can
be fixed by adding explicit return after abort, but it's not shinny.

I think that the only way to fix it is improving Want with a new
context "ARGUMENT" that returns function name if the current function
is called to fill arguments for another function. We can check if the
name is one of dispatcher's rules and can decide what we want to do.
I've done a few tests using Want's parent_op_name hidden function and
looks like it's possible. Robin?

-- 
Best regards, Ruslan.


More information about the jifty-devel mailing list