<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />Alcuni anni fa, stavo lavorando alla creazione di uno script per generare automaticamente un piano di campionamento per un'analisi dei sistemi di misurazione in stile attributo. Tutto stava procedendo senza intoppi, fino a quando non mi sono imbattuto in un grosso problema: come potevo fare in modo che lo script aprisse una finestra per generare l'elenco principale "Pass/Fail" delle parti utilizzate, se il numero di parti è stato scelto in fase di esecuzione? Ora, potresti già pensare a un modo semplice per farlo. Tuttavia, sono ancora orgoglioso del metodo che ho ideato e lo condividerò in questo post sul blog.
Nascoste nella parte Programmazione del JSL Scripting Index ci sono 2 voci apparentemente innocue: Eval e Parse. Queste funzioni consentono a uno scripter furbo di eseguire una stringa come se fosse un pezzo di codice. Essere in grado di farlo ha implicazioni sconcertanti. In questo modo puoi anche risolvere il mio problema di prima.
Scaviamo costruendo un semplice script:
//sezione 1:
//ottenere i criteri pass/fail per una parte
//inizializza alcune variabili
io = 1 ;
listParti = {} ;
//crea una finestra modale per ottenere i criteri
Nuova finestra ( "Ottieni elenco Pass/Fail" ,
<< Modale ,
Casella di riepilogo H (
Casella di riepilogo V (
Casella di formazione ( 2 ,
Casella di testo ( char ( io )) , listParti [ io ] = Casella di modifica del testo ( "Passaggio" ) ,
Scatola dei bottoni ( "OK" , listParti [ io ] = listParti [ io ] << Ottieni testo ; ) , Scatola dei bottoni ( "Annulla" )
)
)
)
) ;
// guarda la lista
spettacolo ( listParti [ io ]) ;
Assicurati di visualizzare il registro, quindi esegui questo script. Lo script stesso mostra una finestra e chiede, solo per una parte, se la parte è un "Riuscito" o un "Fallito". Quando si preme il pulsante OK, qualunque testo sia nella finestra viene passato all'i th posizione nell'elenco listParts e listParts viene visualizzato nel registro. Memorizzare i risultati in un elenco di solo 1 elemento sembra un po' sciocco per ora, ma ha senso quando abbiamo più di una parte per cui memorizzare i criteri Pass/Fail. Guarda l'esempio qui sotto, per come appare lo script per 3 parti:
//sezione 2:
//ripetizione dello script precedente, ma acquisizione dei criteri per 3 parti
io = 1 ;
listParti = {} ;
Nuova finestra ( "Ottieni elenco Pass/Fail" ,
<< Modale ,
Casella di riepilogo H (
Casella di riepilogo V (
Casella di formazione ( 2 ,
Casella di testo ( char ( 1 )) , listParti [ 1 ] = Casella di modifica del testo ( "Passaggio" ) ,
Casella di testo ( char ( 2 )) , listParti [ 2 ] = Casella di modifica del testo ( "Passaggio" ) ,
Casella di testo ( char ( 3 )) , listParti [ 3 ] = Casella di modifica del testo ( "Passaggio" ) ,
Scatola dei bottoni ( "OK" , per ( io = 1 , io <= 3 , io ++, listParti [ io ] = listParti [ io ] << Ottieni testo ; )) , Scatola dei bottoni ( "Annulla" )
)
)
)
) ;
spettacolo ( listParti ) ;
Ma non abbiamo ancora risolto il problema. Come possiamo fare in modo che questo script mostri un numero dinamico di caselle di testo, basato su un numero arbitrario di parti, che non è noto fino a quando lo script non viene eseguito e potrebbe essere diverso ogni volta che lo script viene eseguito? Entra Eval e Parse, i suddetti prodigi, in soccorso. Dai un'occhiata al seguente codice:
//sezione 3:
//determina il numero di parti
Nuova finestra ( "Quante parti?" ,
<< Modale ,
no = Casella di modifica del numero ( 10 ) ,
Scatola dei bottoni ( "OK" , numParti = no << Ottenere ; )
) ;
spettacolo ( numParti ) ;
listParti = {} ;
//Crea la prima parte dello script per la finestra modale
// Sequenza di caratteri di escape per " is \!"
UN = "
Nuova finestra(\!"Ottieni elenco Pass/Fail\!",
<
Casella di riepilogo H(
Casella di riepilogo V(
Riquadro formazione( 2,
" ;
//for loop crea la seconda porzione, che costruisce tante caselle di input quante sono le parti
//|| è la scorciatoia per concatenare
B = "" ;
per ( io = 1 , io <= numParti , io ++,
b1 = char ( "Casella di testo(car(" || char ( io ) || ")), listaParti[" || char ( io ) || "] = Casella di modifica del testo(\!"Pass\!")," ) ;
B = B || b1 ;
) ;
//crea l'ultima parte dello script per la finestra modale
C = "
Pulsante Box(\!"OK\!", for (i = 1, i <=numParts, i++, listParts = listaParti << Ottieni testo;)), Casella pulsante(\!"Annulla\!")
)
)
)
)
" ;
//combina parti dello script ed esegue
D = UN || B || C ;
eval ( analizzare ( D )) ;
//guarda cosa è stato creato
spettacolo ( D ) ;
spettacolo ( listParti ) ;
Innanzitutto, c'è una sezione per chiedere all'utente quante parti, che sono memorizzate in numParts. Successivamente, lo script crea tre stringhe separate che assomigliano in modo sospetto a JSL, tranne per il fatto che sono tutte in viola. La prima stringa è solo una copia esatta (con un codice speciale per fare in modo che i caratteri di citazione non finiscano la stringa) dello script da prima, fino alla parte in cui sono inserite le caselle di testo. La seconda parte è un ciclo for per costruire una stringa composta da quante parti sono state inserite in precedenza (numParts) ripetizioni di caselle di testo. La terza sezione sono gli ultimi bit dello script di prima.
Una volta creata questa stringa, li combiniamo ( D = UN || B || C ; ), quindi utilizzare il eval ( analizzare ( D )) ; comando per valutare cosa succede quando JMP analizza la stringa d (la nostra stringa creata dinamicamente con un numero regolabile di caselle di testo) come se la stringa d fosse uno script JSL e non solo una stringa. Guarda il registro per vedere sia il comando super lungo per mostrare molte caselle di testo, sia l'elenco di Pass/Fail che è stato generato (mostrato di seguito se accetti solo i valori predefiniti):
d = "
Nuova finestra(\!"Ottieni elenco Pass/Fail\!",
<
Casella di riepilogo H(
Casella di riepilogo V(
Riquadro formazione( 2,
Casella di testo(char(1)), listParts[1] = Casella di modifica del testo(\!"Pass\!"),Casella di testo(char(2)), listParts[2] = Casella di modifica del testo(\!"Pass\ !"),Casella di testo(char(3)), listParts[3] = Casella di modifica del testo(\!"Pass\!"),Casella di testo(char(4)), listParts[4] = Casella di modifica del testo(\ !"Pass\!"),Casella di testo(char(5)), listParts[5] = Casella di modifica del testo(\!"Pass\!"),Casella di testo(char(6)), listParts[6] = Testo Edit Box(\!"Pass\!"),Text Box(char(7)), listParts[7] = Text Edit Box(\!"Pass\!"),Text Box(char(8)), listParts[ 8] = Casella di modifica del testo(\!"Pass\!"),Casella di testo(char(9)), listParts[9] = Casella di modifica del testo(\!"Pass\!"),Casella di testo(char(10) ), listParts[10] = Text Edit Box(\!"Pass\!"),
Pulsante Box(\!"OK\!", for (i = 1, i <=numParts, i++, listParts = listaParti << Ottieni testo;)), Pulsante Casella(\!"Annulla\!")
)
)
)
)
";
listParts = {"Accetto", "Accetto", "Accetto", "Accetto", "Accetto", "Accetto", "Accetto", "Accetto", "Accetto", "Accetto"};
Prenditi un momento per pensare alle implicazioni, qui. Con questi concetti, puoi creare codice che si regola da solo e quindi si esegue da solo. Script dinamici, autoreferenziali, ricorsivi e folli potrebbero essere solo l'inizio. Con abbastanza tempo e pazienza, potresti probabilmente usare questo concetto per creare Skynet. Ripensandoci, forse non è una buona idea...
Il problema qui è che <
Non puoi inviare messaggi a cose che non sono oggetti e le liste non sono oggetti nello stesso senso in cui, ad esempio, lo sono le tabelle di dati. Di recente ho corretto un bug di lunga data in uno dei componenti aggiuntivi dei miei clienti rendendomi conto che avevo provato a farlo
list<<INSERT item=""></INSERT>
invece di
insert item(list, item)
Penso che molti di noi si confondano sul fatto che gli array associativi SONO oggetti che possono ricevere <
map=associative array(:Name, :Weight);
map<<INSERT item=""></INSERT>
Tornando alla domanda in questione, non sono davvero sicuro del motivo per cui l'esempio utilizza listparts[i]<Re: Eval (), Parse () e Recursion, un'avventura nella meta-programmazione
Ottimo esempio, grazie @Jed_Campbell .Ho un problema che non riesco a risolvere.Viene visualizzato un errore: Send Expects Scriptable Object in access or evaluation of 'List' , {/*####*/"Pass", "Fail"}
Penso che sia questo comando di invio a causare il problema.Ottengo l'errore solo se scelgo più di 1 numero.qualche idea?
listParts = listParts << Get Text;