2010-02-26 5 views
6

J'écris un proc pour créer un en-tête dans un fichier de sortie.Comment traiter en toute sécurité les paramètres optionnels

Actuellement, il doit prendre un paramètre facultatif, qui est un commentaire possible pour l'en-tête.

J'ai fini par coder cela comme un seul paramètre optionnel

proc dump_header { test description {comment = ""}} 

mais je voudrais savoir comment je peux obtenir les mêmes en utilisant args

proc dump_header { test description args } 

Il est assez facile de vérifier args être un seul paramètre vide ($ args == ""), mais ne supporte pas bien le passage de plusieurs paramètres - et j'ai besoin de la vérification négative de toute façon.

+0

Que voulez-vous faire si votre proc est appelée avec plus de 3 arguments: dump_header mytest mydesc {Un commentaire} somethingelse? Traiter quelque chose comme un autre commentaire, le traiter d'une autre manière? –

+0

Il est faux de comparer $ args à une chaîne vide. args est une liste, pas une chaîne. –

+0

Eh bien, ce n'est pas faux en soi, car il va créer une représentation de chaîne, mais cela peut être inutile si vous allez le traiter comme une liste de toute façon –

Répondre

13

Votre définition de proc est incorrecte (vous obtiendrez le message d'erreur too many fields in argument specifier "comment = """). Devrait être:

proc dump_header { test description {comment ""}} { 
    puts $comment 
} 

Si vous souhaitez utiliser args, vous pouvez examiner la llength de celui-ci:

proc dump_header {test desc args} { 
    switch -exact [llength $args] { 
     0 {puts "no comment"} 
     1 {puts "the comment is: $args"} 
     default { 
      puts "the comment is: [lindex $args 0]" 
      puts "the other args are: [lrange $args 1 end]" 
     } 
    } 
} 

Vous pouvez également passer des paires nom-valeur dans une liste:

proc dump_header {test desc options} { 
    # following will error if $options is an odd-length list 
    array set opts $options 

    if {[info exists opts(comment)]} { 
     puts "the comment is: $opts(comment)" 
    } 
    puts "here are all the options given:" 
    parray opts 
} 
dump_header "test" "description" {comment "a comment" arg1 foo arg2 bar} 

Certains préfèrent une combinaison de args et des paires nom-valeur (a la Tk)

proc dump_header {test desc args} { 
    # following will error if $args is an odd-length list 
    array set opts $args 
    if {[info exists opts(-comment)]} { 
     puts "the comment is: $opts(-comment)" 
    } 
    parray opts 
} 
dump_header "test" "description" -comment "a comment" -arg1 foo -arg2 bar 
+0

Merci. Pour d'autres cas, je pense que je préférerais les paires nom-valeur ... mais dans ce cas je suppose que votre réponse se traduit par "gérer tous les cas que vous devez traiter comme un tableau". Ce qui est bien. – itj

5

J'utilise la bibliothèque cmdline de tcllib pour effectuer l'analyse des options.

Voici l'exemple de la documentation cmdline:

set options { 
    {a   "set the atime only"} 
    {m   "set the mtime only"} 
    {c   "do not create non-existent files"} 
    {r.arg "" "use time from ref_file"} 
    {t.arg -1 "use specified time"} 
} 
set usage ": MyCommandName \[options] filename ...\noptions:" 
array set params [::cmdline::getoptions argv $options $usage] 

if { $params(a) } { set set_atime "true" } 
set has_t [expr {$params(t) != -1}] 
set has_r [expr {[string length $params(r)] > 0}] 
if {$has_t && $has_r} { 
    return -code error "Cannot specify both -r and -t" 
} elseif {$has_t} { 
    ... 
} 

Ainsi, dans votre cas, vous utilisez juste args à la place de argv dans l'exemple ci-dessus.

1

Il doit être mentionné explicitement que args est un mot spécial dans Tcl qui, lorsqu'il est utilisé à la fin de la liste d'arguments, contient une liste de tous les arguments restants. Si aucun args n'est donné, alors aucune erreur n'est produite (contrairement à tout autre nom de variable, qui serait considéré comme un argument obligatoire).

Je cherchais un moyen d'avoir des fonctionnalités similaires à kwargs (arguments optionnels paire clé-valeur) de python, et quelque chose qui fonctionne est bien (semblable au dernier exemple de Glenn):

proc my_proc {positional_required1 {positional_optional1 "a_string"} args} { 
    # Two optional arguments can be given: "opt1" and "opt2" 
    if {![string equal $args ""]} { 
     # If one or more args is given, parse them or assign defaults. 
     array set opts $args 
     if {[info exists opts(opt1)]} { set opt1 $opts(opt1) } else { set opt1 0 } 
     if {[info exists opts(op2)]} { set opt2 $opts(opt2) } else { set opt2 -1 } 
    } else { 
     # If no args are given, assign default values. 
     set op1 0 
     set op2 -1 
    } 
    # DO STUFF HERE 
} 

et peut être appelé comme:

my_proc "positional_required1_argument" 
# OR 
my_proc "positional_required1_argument" "a_string" 
# OR 
my_proc "positional_required1_argument" "a_string" opt1 7 
# OR 
my_proc "positional_required1_argument" "a_string" opt1 7 opt2 50 
# etc. 

un inconvénient potentiel (comme je l'ai actuellement implémentés il) est que si un utilisateur passe une option valeur clé non approuvée, il n'y a pas d'erreur.

Questions connexes