From: <pau...@us...> - 2007-07-24 18:10:10
|
Revision: 978 http://svn.sourceforge.net/everydevel/?rev=978&view=rev Author: paul_the_nomad Date: 2007-07-24 11:10:03 -0700 (Tue, 24 Jul 2007) Log Message: ----------- Amendments to URL processing code Modified Paths: -------------- trunk/ebase/lib/Everything/HTTP/Apache.pm trunk/ebase/lib/Everything/HTTP/Request.pm trunk/ebase/lib/Everything/HTTP/URL/Deconstruct.pm trunk/ebase/lib/Everything/HTTP/URL/Test/Deconstruct.pm trunk/ebase/lib/Everything/HTTP/URL.pm Property Changed: ---------------- trunk/ebase/ Property changes on: trunk/ebase ___________________________________________________________________ Name: svk:merge - 16c2b9cb-492b-4d64-9535-64d4e875048d:/wip/ebase:1030 1b7afbaf-3eae-422c-ad05-e2bef7c06a0f:/wip/ebase:981 a6810612-c0f9-0310-9d3e-a9e4af8c5745:/ebase/offline:17930 + 16c2b9cb-492b-4d64-9535-64d4e875048d:/wip/ebase:1030 1b7afbaf-3eae-422c-ad05-e2bef7c06a0f:/wip/ebase:982 a6810612-c0f9-0310-9d3e-a9e4af8c5745:/ebase/offline:17930 Modified: trunk/ebase/lib/Everything/HTTP/Apache.pm =================================================================== --- trunk/ebase/lib/Everything/HTTP/Apache.pm 2007-07-24 18:08:52 UTC (rev 977) +++ trunk/ebase/lib/Everything/HTTP/Apache.pm 2007-07-24 18:10:03 UTC (rev 978) @@ -9,6 +9,8 @@ use strict; use warnings; +use Carp; +#BEGIN { $SIG{__WARN__} = \&Carp::cluck;} ## initialise Everything::HTTP::URL->set_default_sub( \&Everything::HTML::linkNode ); @@ -24,9 +26,11 @@ ## scriptname for CGI my $e = Everything::HTTP::Request->new( "$db:$user:$password:$host", \%options ); - create_url_parsers( $r, $e ) - unless Everything::HTTP::URL->isset_url_parsers; + $e->get_nodebase->resetNodeCache; + + create_url_parsers( $r, $e ); + ## sets up variables for serving web pages mostly pulled from db $e->setup_standard_system_vars(); @@ -47,17 +51,16 @@ $e->set_node_from_cgi; - if ( !$e->get_node ) { - my $node = Everything::HTTP::URL->parse_url($r); + if ( !$e->get_node ) { - if ( $node && !ref $node ) { - return NOT_FOUND; - } - else { - $e->set_node($node); - } - } + Everything::HTTP::URL->modify_request($r->path_info, $e); + my $node = $e->get_node; + if ( $node && !ref $node ) { + return NOT_FOUND; + } + } + ### if we haven't returned find the default node if ( !$e->get_node && ( $r->path_info eq '/' || $r->path_info eq '' ) ) { my $default_node_id = $e->get_system_vars->{default_node}; @@ -99,9 +102,24 @@ ## parse the URL ## setup url processing + Everything::HTTP::URL->clear_request_modifiers; + Everything::HTTP::URL->clear_node_to_url_subs; + + Everything::HTTP::URL->register_request_modifier( + sub { + my ( $url, $e ) = @_; + + return unless $url eq '/location/'; + my $node = $e->get_nodebase->getNode( 0 ); + $e->set_node ($node); + return 1; + + }); + my @url_config = $r->dir_config->get('everything-url'); return unless @url_config; + while ( my ( $schema, $linker_arg ) = splice( @url_config, 0, 2 ) ) { my $url_parser = Everything::HTTP::URL::Deconstruct->new( @@ -113,12 +131,16 @@ ); $url_parser->set_schema($schema); $url_parser->make_url_gen; - $url_parser->register_url_parser; + $url_parser->make_modify_request; $url_parser->create_nodetype_rule( $url_parser->make_link_node, $linker_arg ); } + + my $link_node = Everything::HTTP::URL->create_linknode; no warnings 'redefine'; - *Everything::HTML::linkNode = Everything::HTTP::URL->create_linknode; + + *Everything::HTML::linkNode = sub { my $node = shift; $Everything::DB->getRef( $node ); $link_node->( $node, @_ ) }; + use warnings 'redefine'; } Modified: trunk/ebase/lib/Everything/HTTP/Request.pm =================================================================== --- trunk/ebase/lib/Everything/HTTP/Request.pm 2007-07-24 18:08:52 UTC (rev 977) +++ trunk/ebase/lib/Everything/HTTP/Request.pm 2007-07-24 18:10:03 UTC (rev 978) @@ -178,8 +178,8 @@ $self, 'user'; tie $Everything::HTML::VARS, "Everything::HTML::Environment::Variable", $self, 'user_vars'; - $Everything::HTML::NODE = $self->get_node; - $Everything::HTML::GNODE = $self->get_node; + tie $Everything::HTML::NODE, "Everything::HTML::Environment::Variable", $self, 'node'; + $Everything::HTML::GNODE = $Everything::HTML::NODE; *Everything::HTML::HTMLVARS = $self->get_system_vars; *Everything::HTML::GLOBAL = {}; $Everything::HTML::AUTH = $self->get_authorisation; Modified: trunk/ebase/lib/Everything/HTTP/URL/Deconstruct.pm =================================================================== --- trunk/ebase/lib/Everything/HTTP/URL/Deconstruct.pm 2007-07-24 18:08:52 UTC (rev 977) +++ trunk/ebase/lib/Everything/HTTP/URL/Deconstruct.pm 2007-07-24 18:10:03 UTC (rev 978) @@ -1,14 +1,15 @@ package Everything::HTTP::URL::Deconstruct; use strict; -use base 'Everything::HTTP::URL'; +use base 'Class::Accessor::Fast', 'Everything::HTTP::URL'; use Data::Dumper; use List::MoreUtils qw(zip); use URI; use SUPER; +__PACKAGE__->follow_best_practice; __PACKAGE__->mk_accessors( - qw(re path_vars schema rule attributes tokens urlifier requested_node_id requested_node_ref url_gen matches nodebase ) + qw(re path_vars schema rule attributes tokens urlifier requested_node_id requested_node_ref url_gen matches nodebase location) ); #### DISPATCH TABLE FOR DECODING URLS @@ -19,8 +20,8 @@ my $decode_attributes = { type => sub { - my ( $self, $attribute_value ) = @_; - my $type = $self->get_nodebase->getType( $attribute_value->[1] ); + my ( $nodebase, $attribute_value ) = @_; + my $type = $nodebase->getType( $attribute_value->[1] ); return 'type_nodetype', $type->{node_id}; }, __DEFAULT__ => sub { return @{ $_[1] }; }, @@ -38,8 +39,22 @@ __DEFAULT__ => sub { return $_[0]->{ $_[1] } }, }; +sub make_modify_request { + my $self = shift; + my $sub = sub { + my ( $url, $e ) = @_; + return unless $self->match($url); + my $node = $self->process($e); + $e->set_node($node); + return 1; + }; + + $self->register_request_modifier($sub); + +} + sub process { - my $self = shift; + my ( $self, $e ) = @_; my @matches = @{ $self->get_matches }; my %node_params = (); while ( my ( $attribute, $value ) = splice @matches, 0, 2 ) { @@ -47,12 +62,13 @@ my $action = $decode_attributes->{ $attribute->[0] } || $decode_attributes->{__DEFAULT__}; ( $attribute, $value ) = - $action->( $self, compulsory_value( $attribute, $value ) ); + $action->( $e->get_nodebase, compulsory_value( $attribute, $value ) ); $node_params{$attribute} = $value; } - my $node = $self->make_requested_node_ref( \%node_params ); + my $node = + $self->make_requested_node_ref( \%node_params, $e->get_nodebase ); return $node; } @@ -113,7 +129,8 @@ } sub make_link_node { - my $self = shift; + my $self = shift; + my $url_gen = $self->get_url_gen; sub { my ( $node, $title, $params, $scripts ) = @_; @@ -123,7 +140,7 @@ # We do this instead of calling getRef, because we only need the node # table data to create the link. - $node = $self->get_nodebase->getNode( $node, 'light' ) + $Everything::HTML::DB->getNode( $node, 'light' ) unless ( ref $node ); return "" unless ref $node; @@ -136,7 +153,7 @@ my $scripts = handle_scripts($scripts); - $link = "<a href=" . $self->get_url_gen->( $params, '', $node ) . $tags; + $link = "<a href=" . $url_gen->( $params, '', $node ) . $tags; $link .= " " . $scripts if ( $scripts ne "" ); $link .= ">$title</a>"; @@ -220,9 +237,9 @@ ## Returns nothing of consequence. sub make_requested_node_ref { - my ( $self, $matches ) = @_; + my ( $self, $matches, $nodebase ) = @_; - my $nodes = $self->get_nodebase->getNodeWhere($matches); + my $nodes = $nodebase->getNodeWhere($matches); return unless $nodes; if ( @$nodes == 1 ) { @@ -304,10 +321,10 @@ =head1 SYNOPSIS - use Everything::HTTP::URLProcess::Deconstruct; + use Everything::HTTP::URL::Deconstruct; my $r = Apache->request; my $e = Everything::HTTP::Request->new; - my $processor = Everything::HTTP::URLProcess::Deconstruct->new({r => $r, e => $e}); + my $processor = Everything::HTTP::URL::Deconstruct->new({r => $r, e => $e}); $processor->set_schema('/path/text/:node_id'); @@ -335,22 +352,7 @@ =cut -=head2 C<< $m->require_param NAME, VALUE >> -NOT USED - -This internal method returns the regular expression -to match a HTTP query parameter and its name. - -NAME is the name of the key into which the value will -be captured. - -VALUE is the regular expression that will match -the value. - -=cut - - =head2 C<< $m->make_regex >> This is the internal method that implements the meat @@ -362,19 +364,17 @@ =head2 C<< $m->match($url) >> -This is also an internal method. - Returns a list of captured values if the request matches. If the request matches but does not capture anything, -a single 1 is returned. This is ugly but such is life. +a single 1 is returned. =cut -=head2 C<< $m->process($url) >> +=head2 C<< $m->process ($e) >> -Takes a URL. Amends the Everything::HTTP::Request object in place setting the requested node to the appropriate values. +Takes an Everything::HTTP::Request object and modifies it by setting the 'node',attribute. It should be called after 'match' and uses the 'matches' attribute to select the node. =cut Modified: trunk/ebase/lib/Everything/HTTP/URL/Test/Deconstruct.pm =================================================================== --- trunk/ebase/lib/Everything/HTTP/URL/Test/Deconstruct.pm 2007-07-24 18:08:52 UTC (rev 977) +++ trunk/ebase/lib/Everything/HTTP/URL/Test/Deconstruct.pm 2007-07-24 18:10:03 UTC (rev 978) @@ -10,7 +10,7 @@ ## needs to be rewritten -sub test_z_process : Test(5) { +sub test_z_process : Test(4) { my $self = shift; can_ok($self->{class}, 'process') || return; @@ -19,25 +19,23 @@ my $instance = $self->{instance}; - $instance->set_request($mock); - $instance->get_request->set_always('get_nodebase',$mock) - ->set_always('get_cgi', $mock); $mock->set_true('param'); $instance->mock('make_requested_node_ref' => sub {$_[0]->set_requested_node_ref($mock) }); - $instance->set_always('get_nodebase', $mock); + $mock->set_always('getType', $mock); $instance->set_schema('/node/:node_id'); - ok ($instance->process() ); - my ($method, $args) = $instance->next_call; - is ($method, 'get_nodebase', '...gets nodebase object.'); + my $fake_request = Test::MockObject->new; + $fake_request->set_always( get_nodebase => $mock ); + ok ($instance->process( $fake_request ) ); + $instance->set_schema('/node/:type'); $instance->get_nodebase->set_always('getType', {node_id => 111}); $instance->set_always('get_matches', [['type_nodetype'], 222]); - ok ($instance->process() ); - my ($method, $args) = $instance->next_call; + ok ($instance->process( $fake_request ) ); + my ($method, $args) = $instance->next_call(); is ($method, 'make_requested_node_ref', '...should call node making method.'); @@ -94,6 +92,7 @@ $instance->make_url_gen; my $mock = Test::MockObject->new; + *Everything::HTML::DB = \$mock; $mock->{node_id} = 111; $mock->{title} = "Random node"; @@ -104,7 +103,7 @@ my $linkNode = $instance->make_link_node; is(ref $linkNode, 'CODE', '...creates a code ref'); - is( $linkNode->(1), '<a href="/node/111">Random node</a>', "linkNode" ); + is( $linkNode->($mock), '<a href="/node/111">Random node</a>', "linkNode" ); $mock->{node_id} = 222; $mock->{title} = "Another Random Node"; is( $linkNode->($mock), '<a href="/node/222">Another Random Node</a>', @@ -148,7 +147,7 @@ my $linkNode = $instance->make_link_node; is(ref $linkNode, 'CODE', '...creates a code ref'); - is( $linkNode->(1), '<a href="/node/Random%20node">Random node</a>', "...testing node url creation." ); + is( $linkNode->($mock), '<a href="/node/Random%20node">Random node</a>', "...testing node url creation." ); ## testing title Modified: trunk/ebase/lib/Everything/HTTP/URL.pm =================================================================== --- trunk/ebase/lib/Everything/HTTP/URL.pm 2007-07-24 18:08:52 UTC (rev 977) +++ trunk/ebase/lib/Everything/HTTP/URL.pm 2007-07-24 18:10:03 UTC (rev 978) @@ -1,13 +1,63 @@ package Everything::HTTP::URL; -use base 'Class::Accessor::Fast'; -__PACKAGE__->follow_best_practice; -__PACKAGE__->mk_accessors( - qw/request path_info url cgi location requested_node_id requested_node_ref/ -); +=cut -our @select_node_subs = (); -our @url_parsers = (); +=head1 NAME + + Everything::HTTP::URL - process requested urls and turn nodes into urls. + +=head1 SYNOPSIS + + + Everything::HTTP::URL->register_request_modifier( + sub { my ( $url, $e ) = @_; + return unless $url eq '/location/'; + my $node = $e->get_nodebase->getNode( 0 ); + $e->set_node ($node); + return 1; + +}); + + Everything::HTTP::URL->create_url_rule( + sub { my $node = shift; + return 1 if $node->get_title eq '/'; + return + }, + sub { '/location/' } + ); + +Everything::HTTP::URL->set_default_sub( \&Everything::HTML::linkNode ); + + +The apache handler: + +sub handler { + + my $r = shift; # grab the request object; + + my $e = Evertyhing::HTTP::Request->( ...with options....); + + Everything::HTTP::URL->modify_request( $r->path_info, $e ); + + *Everything::HTML::linkNode = Everything::HTTP::URL->create_linknode; + + +} + +=head1 DESCRIPTION + +As you will have noticed all the methods are class methods. This is because all the variables are class variables and they can be modified in httpd.conf or anywhere. It is also because this class is designed to be subclassed, but also to be able to srote all the url parsers and node to url modifiers in the same place. + +=cut + + + +use strict; +use warnings; + + +our @node_to_url_subs = (); +our @request_modifiers = (); our $default_sub; sub new { @@ -20,23 +70,64 @@ } +=head2 C<< create_url_rule >> + +Creates a rule for node to url subs. + +Takes two arguments. + +The first argument is a call back to check whether this rule applies +to this node. The call back is passed the node as an argument and should +return true if this rule applies to the node or false otherwise. + +The second argument is a call back that turns a node into a url. It is passed the node as an argument and returns a string which is the path to url. + +These two arguments are combined into a code reference which is added to the node_to_url_subs attribute and returned. + +=cut + + +sub create_url_rule { + my ( $self, $check_node_cb, $make_url_cb ) = @_; + + my $rule = sub { + return $make_url_cb->( @_ ) if $check_node_cb->( @_ ); + return; + }; + push @node_to_url_subs, $rule; + return $rule; + +} + +=head2 C<< create_nodetype_rule >> + +Creates a rule to test whether a node is of a certain type, if it is then applies the url creation subroutine supplied by the first argument. The second argument is the type name. + +Returns a subroutine reference and pushes it onto the class list of subroutine references that can be retrieved by get_node_to_url_subs. + +=cut + + sub create_nodetype_rule { my ( $self, $sub, $typename ) = @_; - my $rule = sub { + my $select_node = sub { my $node = shift; - $node = $self->get_request->get_nodebase->getNode($node) - unless ref $node; - my $type = $node->{type}; - return unless $type->{title} eq $typename; - return $sub->( $node, @_ ); + return 1 if $node->isa( 'Everything::Node::' . $typename ); + return; }; - push @select_node_subs, $rule; - return $rule; + return $self->create_url_rule( $select_node, $sub ); } + +=head2 C<< create_linknode >> + +Concantenates all the subroutines stored in node_to_url_subs adds the default_sub to the end and returns a code ref. This is supposed to be a replacement for Everything::HTML::linkNode; + +=cut + sub create_linknode { my ($self) = @_; - my @subs = @select_node_subs; + my @subs = @node_to_url_subs; push @subs, $self->get_default_sub if $self->get_default_sub; my $linknode = sub { foreach (@subs) { @@ -48,25 +139,32 @@ } -sub parse_url { - my ( $this, $r ) = @_; - return unless @url_parsers; +=cut - my $matches; - my $node; - PARSERS: - foreach (@url_parsers) { +=head2 C<< modify_request >> - if ( my $m = $_->match( $r->path_info ) ) { +Goes throught the parsers one by one in order and modifies the request object. Stops once a parser returns a true value. If a parser returns a false value keeps going. - ++$matches; - if ( $node = $_->process ) { - last PARSERS; - } - } +Takes two argumnets. The first is the url being request, the second is a Everything::HTTP::Request object. + +Returns a true value if at least one of the request modifiers was successful. + +=cut + +sub modify_request { + my ( $self, $url, $e ) = @_; + + return unless $self->isset_request_modifiers; + + my $found = 0; + + foreach ( @request_modifiers ) { + $found++ if $_->( $url, $e ); + last if $found; } - return $matches if !$node; - return $node; + + return $found if $found; + return; } sub set_default_sub { @@ -81,33 +179,61 @@ } -sub get_select_node_subs { +sub get_node_to_url_subs { - @select_node_subs; + @node_to_url_subs; } -sub get_select_node_subs_ref { +sub clear_node_to_url_subs { - \@select_node_subs; + @node_to_url_subs = (); } -sub set_select_node_subs { +sub get_node_to_url_subs_ref { + \@node_to_url_subs; +} + +sub set_node_to_url_subs { + shift; - @select_node_subs = @_; + @node_to_url_subs = @_; } -sub register_url_parser { +=cut - push @url_parsers, $_[0]; +=head2 C<< register_request_modifier >> +Pushs the argument, which must be subroutine reference onto the request_modifiers array. + + The subroutine/argument is passed two arguments, the first is a path from a url the second is a Everything::HTTP::Request instance. + + Should return true if it wants to be the last subroutine run. + +=cut + + +sub register_request_modifier { + + push @request_modifiers, $_[1]; + } -sub isset_url_parsers { +sub isset_request_modifiers { - return 1 if @url_parsers; + return 1 if @request_modifiers; return; } +sub get_request_modifiers { + + @request_modifiers; +} + +sub clear_request_modifiers { + + @request_modifiers = (); +} + 1; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |