You are viewing a plain text version of this content. The canonical link for it is here.
Posted to rivet-dev@tcl.apache.org by "Hicks, Bob" <BH...@osc.uscg.mil> on 2005/05/03 20:48:37 UTC

Page Controller Pattern (or some such thing)

Now that I have figured out how I can pass things around, I was wondering if
there was a more elegant way to do so.

My index.tcl page has an "if/elseif/else" based on the URL param. That could
get rather ugly and hard to maintain if it gets to any size.

Can I put things into a proc and pass that? Something like:

proc main {} {
	init
	page_switch
}

proc init {} {
	# any globals; which would be a variable that I want to pass
	# to all templates or more than one...
}

proc page_switch {} {
	set page [var get page]
	
	if {$page = "main"} {
		# pass the "page1" proc through here somehow
	} elseif {$page = "page2"} {
		# pass the "page2" proc through here somehow
	}
}

proc page1 {} {
	set title "Main Page"
	set menu "menu1.tpl"
	return vars [list $title $menu] # I have NO idea if this is valid!
}

proc page2 {} {
	set title "Second Page"
	set menu "menu2.tpl"
	return vars [list $title $menu] # I have NO idea if this is valid!
}


That way I can work up the different procs for different pages and pass
multiple values to my templates. That keeps the if/elseif/else readable and
allowing me to totally separate Tcl code from HTML.

Is that too funky? Thoughts and idea welcome!

Bob



---------------------------------------------------------------------
To unsubscribe, e-mail: rivet-dev-unsubscribe@tcl.apache.org
For additional commands, e-mail: rivet-dev-help@tcl.apache.org


Re: Page Controller Pattern (or some such thing)

Posted by Ronnie Brunner <ro...@netcetera.ch>.
I didn't wanna throw in my 2 cents, but since David mentioned Websh, I
can't really resist ;-)

If I translate our Websh implementation to the naming you used in
your examples, my approach looks something like this (I didn't
run the code, but even with the usual typos and with global variables 
(yuck ;-) it should give you an impression of what I mean):

 action default {
    # do some default stuff
 }
 action somepage {
    # do whatever other stuff
 }
 dispatch

Where

 proc action {name code} {
    global actions
    set actions($name) $code
 }
 proc dispatch {} {
    global actions
    # I don't know about rivet, but that's what I've seen in your example ;-)
    load_response data 
    if {![info exists data(action)] || ![info exists actions($data(action))]} {
	set data(action) default
    }
    if {[info exists actions($data(action))]} {
	uplevel 1 $actions($data(action))
    }
 }

This results in a well structuerd list of available pages (whatever you 
"register" with usinge the proc page and always calls your default page
(fallback when no or an invalid page is in the URL)

Regards
Ronnie

> "Robert S. Sciuk" <ro...@controlq.com> writes:
> 
> > My database dispatcher looks like this ...
> > 
> >        proc dispatch { } {
> >                 load_response dta
> >                 switch -exact $dta(action) {
> >                         Add    { fst::rec_add }
> >                         Delete { fst::rec_del }
> >                         Find   { fst::rec_find }
> >                         Update { fst::rec_update }
> >                         First  { fst::rec_First }
> >                         Next   { fst::rec_Next }
> >                         Prev   { fst::rec_Prev }
> >                         Last   { fst::rec_Last }
> >                 }
> >         }
> 
> > The form sets a hidden variable (action) with the appropriate
> > action, according to the user button requested, and the appropriate
> > procedure is called.  In addition, the form action of the calling
> > page is simply a reference to the dispatch function.  Something
> > similar might be used for a page generation mechanism, and it is
> > trivial to change/extend.
> 
> That's a very sensible pattern.  It's also what the Websh guys use,
> more or less.
> 
> I have a dispatch package sitting around that I ought to include with
> Rivet - it automates some of this.
> 

-----------------------------------------------------------------------
Ronnie Brunner                              ronnie.brunner@netcetera.ch
Netcetera AG, 8040 Zuerich, phone +41 44 247 79 79 fax +41 44 247 70 75

---------------------------------------------------------------------
To unsubscribe, e-mail: rivet-dev-unsubscribe@tcl.apache.org
For additional commands, e-mail: rivet-dev-help@tcl.apache.org


Re: Page Controller Pattern (or some such thing)

Posted by "David N. Welton" <da...@dedasys.com>.
"Robert S. Sciuk" <ro...@controlq.com> writes:

> My database dispatcher looks like this ...
> 
>        proc dispatch { } {
>                 load_response dta
>                 switch -exact $dta(action) {
>                         Add    { fst::rec_add }
>                         Delete { fst::rec_del }
>                         Find   { fst::rec_find }
>                         Update { fst::rec_update }
>                         First  { fst::rec_First }
>                         Next   { fst::rec_Next }
>                         Prev   { fst::rec_Prev }
>                         Last   { fst::rec_Last }
>                 }
>         }

> The form sets a hidden variable (action) with the appropriate
> action, according to the user button requested, and the appropriate
> procedure is called.  In addition, the form action of the calling
> page is simply a reference to the dispatch function.  Something
> similar might be used for a page generation mechanism, and it is
> trivial to change/extend.

That's a very sensible pattern.  It's also what the Websh guys use,
more or less.

I have a dispatch package sitting around that I ought to include with
Rivet - it automates some of this.

-- 
David N. Welton
 - http://www.dedasys.com/davidw/

Apache, Linux, Tcl Consulting
 - http://www.dedasys.com/

---------------------------------------------------------------------
To unsubscribe, e-mail: rivet-dev-unsubscribe@tcl.apache.org
For additional commands, e-mail: rivet-dev-help@tcl.apache.org


Re: Page Controller Pattern (or some such thing)

Posted by "Robert S. Sciuk" <ro...@controlq.com>.



On Tue, 3 May 2005, Damon Courtney wrote:

> Date: Tue, 03 May 2005 14:27:20 -0500
> From: Damon Courtney <dc...@hmssoftware.com>
> To: "Hicks, Bob" <BH...@osc.uscg.mil>
> Cc: rivet-dev@tcl.apache.org
> Subject: Re: Page Controller Pattern (or some such thing)
>
> Bob,
>
>     I usually do something like this:
>
> load_response
>
> if {![info exists response(page)]} {
>     set response(page) main
> }
>
> $response(page)
>
>
>     With this, if no page was passed in, we call the "main" proc.
> Otherwise, we call whatever proc is associated with the page.  This has
> one failure in that if you have procs that have no arguments, someone
> malicious can use a page that refers to your proc and call it.  If you
> were worried about this (I don't usually), you could do something like:
>
> namespace eval page {
>
> proc main {} {
>
> }

My database dispatcher looks like this ...

       proc dispatch { } {
                load_response dta
                switch -exact $dta(action) {
                        Add    { fst::rec_add }
                        Delete { fst::rec_del }
                        Find   { fst::rec_find }
                        Update { fst::rec_update }
                        First  { fst::rec_First }
                        Next   { fst::rec_Next }
                        Prev   { fst::rec_Prev }
                        Last   { fst::rec_Last }
                }
        }

The form sets a hidden variable (action) with the appropriate action,
according to the user button requested, and the appropriate procedure is
called.  In addition, the form action of the calling page is simply a
reference to the dispatch function.  Something similar might be used for a
page generation mechanism, and it is trivial to change/extend.

Hope this helps ...

Cheers,
Rob.

-- 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
Robert S. Sciuk		http://www.controlq.com		259 Simcoe St. S.
Control-Q Research	tel: 905.576.8028		Oshawa, Ont.
rob@controlq.com	fax: 905.576.8386  		Canada, L1H 4H3

---------------------------------------------------------------------
To unsubscribe, e-mail: rivet-dev-unsubscribe@tcl.apache.org
For additional commands, e-mail: rivet-dev-help@tcl.apache.org


Re: Page Controller Pattern (or some such thing)

Posted by Damon Courtney <dc...@hmssoftware.com>.
Bob,

    I usually do something like this:

load_response

if {![info exists response(page)]} {
    set response(page) main
}

$response(page)


    With this, if no page was passed in, we call the "main" proc.  
Otherwise, we call whatever proc is associated with the page.  This has 
one failure in that if you have procs that have no arguments, someone 
malicious can use a page that refers to your proc and call it.  If you 
were worried about this (I don't usually), you could do something like:

namespace eval page {

proc main {} {

}

proc page1 {} {

}

proc page2 {} {

}

} ; ## namespace eval page

load_response

if {![info exists response(page)]} {
    set response(page) main
}

page::$response(page)

    Then, all you need to do to add a new page proc is put it in the 
page namespace.  Any procs outside of the page namespace can't be called 
directly via the response(page) mechanism.  This is how I write EVERY 
Rivet application.  I rarely, if ever, have separate html documents.  My 
applications usually consist of one, single html file and a bunch of 
.tcl files that get sourced in and run whatever page is appropriate.  
Heck, my html file is usually just a little stub that does what you see 
in the above code. 0-]

Damon


Hicks, Bob wrote:

>Now that I have figured out how I can pass things around, I was wondering if
>there was a more elegant way to do so.
>
>My index.tcl page has an "if/elseif/else" based on the URL param. That could
>get rather ugly and hard to maintain if it gets to any size.
>
>Can I put things into a proc and pass that? Something like:
>
>proc main {} {
>	init
>	page_switch
>}
>
>proc init {} {
>	# any globals; which would be a variable that I want to pass
>	# to all templates or more than one...
>}
>
>proc page_switch {} {
>	set page [var get page]
>	
>	if {$page = "main"} {
>		# pass the "page1" proc through here somehow
>	} elseif {$page = "page2"} {
>		# pass the "page2" proc through here somehow
>	}
>}
>
>proc page1 {} {
>	set title "Main Page"
>	set menu "menu1.tpl"
>	return vars [list $title $menu] # I have NO idea if this is valid!
>}
>
>proc page2 {} {
>	set title "Second Page"
>	set menu "menu2.tpl"
>	return vars [list $title $menu] # I have NO idea if this is valid!
>}
>
>
>That way I can work up the different procs for different pages and pass
>multiple values to my templates. That keeps the if/elseif/else readable and
>allowing me to totally separate Tcl code from HTML.
>
>Is that too funky? Thoughts and idea welcome!
>
>Bob
>
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: rivet-dev-unsubscribe@tcl.apache.org
>For additional commands, e-mail: rivet-dev-help@tcl.apache.org
>
>  
>



---------------------------------------------------------------------
To unsubscribe, e-mail: rivet-dev-unsubscribe@tcl.apache.org
For additional commands, e-mail: rivet-dev-help@tcl.apache.org