• upvar and uplevel - help

    From sundar@user2276@newsgrouper.org.invalid to comp.lang.tcl on Sun Mar 16 04:37:56 2025
    From Newsgroup: comp.lang.tcl


    ```
    proc render {data css template} {
    # Generate scoped CSS and get container class
    lassign [scope_css $css] scoped_css container_class

    # Create a container with the scoped CSS
    set result [div [list class $container_class] \
    [style {} $scoped_css] \
    [eval $template]]
    return $result
    }
    proc mytest::card_page {} {
    variable card_styles
    # Create some sample cards using your card proc
    set cards_data [list \
    [dict create \
    title "Performance" \
    body "Track your metrics..." \
    footer [a {href "#"} "View Details"]] \
    [dict create \
    title "Revenue" \
    body "Monitor revenue..." \
    footer [a {href "#"} "View Report"]]
    ]
    set template {
    div {class "card-grid"} \
    {*}[lmap card $data {
    dict with card {}
    article {class "card"} \
    [h3 {class "card-title"} $title] \
    [div {class "card-content"} $body] \
    [expr {$footer ne "" ?
    [div {class "card-footer"} $footer] : ""}]
    }]
    }
    return [render $cards_data $card_styles $template]
    }
    ```
    Hello Tclers,
    In the above code I want to use 'upvar' and 'uplevel' in the 'template' so as to use the variables declared in the surrounding scope (cards_data & card_styles, in this case),
    instead of passing it as arguments to the 'render' function.
    One way is,
    ```
    set template {
    upvar cards_data data
    div {class "card-grid"} \
    .....
    }
    ```
    But is there a way to make the 'upvar' use any variable (table_data, list_data)
    where we don't have to make the required changes at each place where the 'templeat'
    is needed?
    Any other suggestion to refactor is also most welcome.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Arjen@user153@newsgrouper.org.invalid to comp.lang.tcl on Sun Mar 16 14:33:16 2025
    From Newsgroup: comp.lang.tcl


    sundar <user2276@newsgrouper.org.invalid> posted:


    But is there a way to make the 'upvar' use any variable (table_data, list_data)
    where we don't have to make the required changes at each place where the 'templeat'
    is needed?
    Any other suggestion to refactor is also most welcome.

    Yes, most certainly:

    ```
    proc render {v w} {
    upvar $v _v
    upvar $w _w

    set _v "V 1"
    set _w "W 2"
    }

    # Before render ...

    set v A
    set w B

    puts "$v -- $w"

    render v w ;# Pass the names, not the values - then we can change the values

    puts "$v -- $w"
    ```

    It is a rather silly example, but the secret is that you pass the *name*
    of the variables and not the value.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sundar@user2276@newsgrouper.org.invalid to comp.lang.tcl on Mon Mar 17 03:28:56 2025
    From Newsgroup: comp.lang.tcl


    It is a rather silly example, but the secret is that you pass the *name*
    of the variables and not the value.

    a small nudge from a Guru is a giant leap for a rookie :)
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sundar@user2276@newsgrouper.org.invalid to comp.lang.tcl on Wed Mar 19 08:42:46 2025
    From Newsgroup: comp.lang.tcl


    It is a rather silly example, but the secret is that you pass the *name*
    of the variables and not the value.

    I have refactored the 'render' proc to use 'upvar' and this is turning out to be
    more useful in simplifying all 'components',
    ```
    proc render {data css template} {
    upvar $data _data
    upvar $css _css
    upvar $template _template
    # Generate scoped CSS and get container class
    lassign [scope_css $_css] scoped_css container_class

    # Create a container with the scoped CSS
    set result [div [list class $container_class] \
    [style {} $scoped_css] \
    [eval $_template]]
    return $result
    }
    ```
    as an example here is 'pagination' component,
    ```
    ...
    dict set data headers {Name Email Status {Last Active}}
    set page 1 ;# Current page (default to 1)
    set page_size 5 ;# Rows per page

    set template {
    upvar page _page
    upvar page_size _page_size
    table {class "pagination-table"} \
    [tr {} \
    {*}[lmap header [dict get $_data headers] {
    th {} $header
    }]] \
    {*}[lmap row [lrange [dict get $_data rows] [expr {($_page - 1) * $_page_size}] [expr {$_page * $_page_size - 1}]] {
    tr {} \
    {*}[lmap cell $row {
    td {} $cell
    }]
    }] \
    [div {class "pagination-nav"} \
    [if {$_page > 1} {
    a [list href "/pagination?page=[expr {$_page - 1}]" rel "prev"] "Previous"
    }] \
    [span {} "Page $_page"] \
    [if {$_page * $_page_size < [llength [dict get $_data rows]]} {
    a [list href "/pagination?page=[expr {$_page + 1}]" rel "next"] "Next"
    }]]
    }
    return [render data table_pa_styles template]
    }
    ```
    --- Synchronet 3.20c-Linux NewsLink 1.2