Have you thought about using arrays?  Very easy to make a single array to
hold all kinds of state info:

  form(varname1,value) = the value
  form(varname1,error) = the error
  form(varname1,default) = default value
  form(varname1,vproc) = validation proc
  ...

Then you only have to worry about passing around the form array.  We do:

proc blah {_form} {
  upvar $_form form

  (mess with form array)
}

Very flexible since all your interfaces don't have to change when you want
to add a new capability.

Good luck!
Jim

>
> I haven't been able to find much help on this on the web, so I'm turning to
> the mailing list.
> We've been getting terribly frustrated with scoping and passing variables
> around in TCL. I have a form that accepts a lot of inputs and am calculating
> stuff based on those inputs. My problem basically is I want to avoid passing
> all the variables around to all the procs (especially procs that don't even
> use them and just pass them on somewhere else!) or making a global copy of
> every variable.
>
> I think I don't understand uplevel, upvar, global and namespaces etc
> properly, so it would be great if somebody could direct me to some help.
>
> Here's my problem:
> If I use uplevel around a chunk of code, I find it ignores parameters passed
> into the procedure.
>
> Here's what I've been doing: assume I have a main procedure which has
> variables x, y and z.
> I call test2 from this procedure (w is not a variable in the main
> procedure).
>
> test2 is defined as:
> proc test2 {w} {
>         uplevel {
>                 set result [expr w + x +y +z]
>                 return $result
>         }
> }
>
> This proc breaks because w does not exist on the level above.
>
> I then tried to use upvar:
> proc test2 {w} {
>         upvar w w
>         uplevel {
>                 set result [expr w + x +y +z]
>                 return $result
>         }
> }
> This works fine if I call test2 once, but if I call it a 2nd time, I get an
> error telling me w already exists. Unsetting didn't work either because it
> was a link.
>
> My colleague came up with the following fix using namespaces which seems to
> work - he redefines the ACS procedure set_form_variables.
> (apologies to non-ACS people for including ACS code here ;-) )
>
> Is this the best solution? I don't like having to refer to the namespace
> everywhere I need to access x, y and z. Surely there must be a solution
> using uplevel etc.?
>
> I think I really need to learn more about all this kind of stuff - any
> pointers?
>
> cheers,
> Brian
>
> Call this and have it accept product_id with some value.
> ----Cut here----
> > ad_proc ba_set_form_variables {{error_if_not_found_p 1}} {
> >
> >   Exactly the same as set_form_variables, except it sets the variables
> >   in a namespace called "ba_ns"
> >
> > }
> >     if { $error_if_not_found_p == 1} {
> >         uplevel { if { [ns_getform] == "" } {
> >             ns_returnerror 500 "Missing form data"
> >             return
> >         }
> >        }
> >      } else {
> >          uplevel { if { [ns_getform] == "" } {
> >              # we're not supposed to barf at the user but we want to
> > return
> >              # from this subroutine anyway because otherwise we'd get an
> > error
> >              return
> >          }
> >      }
> >   }
> >
> >     # at this point we know that the form is legal
> >     # The variable names are prefixed with a V to avoid confusion with the
> > form variables while checking for naughtiness.
> >     namespace eval ba_ns {
> >         set Vform [ns_getform]
> >         set Vform_size [ns_set size $Vform]
> >         set Vform_counter_i 0
> >         while {$Vform_counter_i<$Vform_size} {
> >                       set Vname [ns_set key $Vform $Vform_counter_i]
> >                       set Vvalue [ns_set value $Vform $Vform_counter_i]
> >                       check_for_form_variable_naughtiness $Vname $Vvalue
> >                       set $Vname $Vvalue
> >                       incr Vform_counter_i
> >                   }
> >               }
> > }
> >
> >
> > proc test1 {} {
> >
> >   set product_id "you won't see this either"
> >   return $::ba_ns::product_id
> >
> > }
> >
> > set product_id "you won't see this"
> >
> > ba_set_form_variables
> >
> > doc_body_append "[test1]"
> ---end----
>

Reply via email to