saving environment for debugging purposes

Hello

I wonder wether there is a way to write a save_environment() routine that would save to a file the content of some variables. And another one recover_environment() that would bring them back in another script

e.g

set variable1 to “My data to save”
set variable2 to “My other data to save”

save_environment(variable1, variable2) – would save the variables with name and content in a file on desktop

then

recover_environment()

would be equivalent to :
set variable1 to “My data to save”
set variable2 to “My other data to save”

But i cannot figure how to get access to the the variable names in the save_environment() routine

Any idea ?

You will have to do:

save_environment({variable1, variable2})

and

set {variable1, variable2} to recover_environment()

The reason for the list (or array) on the first one (or save) is because a handler has to have a specific amount of perimeters. The second one (or recover) is in a set line because you can’t set a variable in a handler and have it intact outside the handler. Example: This will return an error because hello was set inside the handler.

hi()
return hello
on hi()
	set hello to "W"
end hi

I’ll try to work on it.

Here it is.

Saving Script:

set variable1 to "Hello."
set variable2 to "How are you today?"
save_environment({variable1, variable2}, (path to desktop as text) & "Test.file")

on save_environment(thelist, thefile)
	try
		set thedata to open for access thefile with write permission
		set eof of thedata to 0
		write (thelist) to thedata starting at eof as list
		close access thedata
		return true
	on error e
		try
			close access thedata
		end try
		log e
		return false
	end try
end save_environment

Recover Script:

set {variable1, variable2} to recover_environment((path to desktop as text) & "Test.file")

on recover_environment(thefile)
	return (read file thefile as list)
end recover_environment

Thank you for the script and the learnings.

It works great.

I guess from what you said…

…that it is not possible to extend the scope of a variable outside an handler

I also see that i was near your solution but that by trying to optimize it (not having to retype the variables names in the recover routine), i spent a lot of time without going nowhere
So i also learnt that lazyness is not always the best advisor !
Thanks again

It actually is possible to use variables outside the scope of handlers. Therefore you have to declare the variables global. There are two types of variables in general: global ones and local ones. You declare them like this:

local aLocal
global aGlobal

Variables are local by default, so you shouldn’t declare one as a local unless you declared it as a global first.

set v to 1 -- a local variable

global v
set v to 2 -- the global version of v

local v -- switch back to the local one
display dialog "Local v is " & v
--> 1

global v -- switch back to global
display dialog "Global v is " & v
--> 2


If you want to use the global variable, make sure you let AppleScript know you want to use the global one:

on run
global v
set v to 1
displayV()
--> 1

setV(3)
displayV()
--> 3

local v -- switch to local v
set v to 5
display dialog "Local v is " & v
--> 5

displayV()
--> 3
end run

on displayV()
global v
display dialog "Global v is " & v
end displayV

on setV(newV)
global v
set v to newV
end setV

I hope you get the concept of global variables at least a little bit know,
ief2

PS: I’ve written this post on my iPod so please excuse me for my bad spelling. It’s due to the fact that my first language isn’t English and the iPod doesn’t have a good spelling checker. Also excuse me for the bad AppleScript alignment. But since I’m on my iPod, there’'s now way to compile scripts and no easy way to insert a tab.

EDIT: I guess there’s something wrong with the copy/paste function of the iPod Touch. Line endings did not come through in this post. Click “Quote” to see full post. (Can someone explain why my post looks so weird?)

Either way, you still have to type as much.

That’s right. It’s much better to let your handlers return something than making a mess of local and global variables.

@ief2

Thanks for your answer
However i am not sure i could use it to fulfill the initial request

  1. i woud have to make global a variable that was not defined as such (which may be an acceptable price to pay)
  2. i still don’t get how i could access the name of the variable (as opposed to the content) for use in the recovery phase

Something like:


set variable1 to "Hello."
set variable2 to "How are you today?"
set list_of_variables to magic_function( {variable1, variable2,...}) -- where magic_function captures both the strings "variable1" and the content of variable1

save_environment(list_of_variables) --saves to disk

recover_environment() -- can reinitialise "variable1" to the saved content of the old variable1, which i guess is where i would need global variables



{variable1, variable2}

I would think to stick with my idea. Having globals means the script is not flexible, and you have to change it each time you put it into another script.

@Dylan

That’s precisely what i want to avoid by trying to code a reference to the name of the variable, but maybe it is not possible

Anyway, i did use your idea for my needs, so thanks again

In normal scripting files, it’s of course better to use a return value in your handlers. Globals are mostly used if there are other handlers than the on run (like on idle, on open theObjects, on quit).

A little demonstration:

global idleCount

on run
	-- set up idleCount
	-- else you'll get the error "the variable idleCount is not defined"
	-- in the "on idle"-handler
	set idleCount to 1
end run

on idle
	set myBut to missing value
	set myBut to button returned of (display dialog "This dialog has already been displayed for " & idleCount & " times" buttons {"Quit", "OK"} default button 2 giving up after 1)
	
	-- Quit
	if myBut is "Quit" then quit
	
	-- increase idleCount via handler
	-- is the same as
	-- set idleCount to idleCount + 1
	increaseIdleCount()
	
	return 1
end idle

on increaseIdleCount()
	set idleCount to idleCount + 1
end increaseIdleCount

Hope it helps,
ief2

hello ief2

Given a variable var_1,

       set var_1 to "my precious data"

Would you know a way to achieve either:

1) a way to get the name of the variable
i.e
my_routine(var_1)

returns the string “var_1”

2) a way to address the content of a variable by its name as string
i.e
my_routine(“var_1”)

returns “my precious data”"

I looked into the AS guide, to no avail

As far as I know, it’s not possible to do such things. For the second one you could do something like:

getVarWithName("var")

on getVarWithName(aString)
	set myScript to "get " & aString
	return (run script myScript)
end getVarWithName

But then again, how would you pass the value of “var” to the script? I don’t know, and I don’t think any of us knows.

If your above script worked, i think i may have had a solution

But it seems it does not work, even if global

global MyVar

set MyVar to "test"

getVarWithName("MyVar")

on getVarWithName(aString)
	set myScript to "get " & aString
	return (run script myScript)
end getVarWithName

→ returns “Variable MyVar is undefined”

There’s a problem of heritance i can’t solve

To be clear: my script does not work!

The script stored in myScript is completely different than the script which creates it. It does not share any variable.

So you will need to pass the variable to the handler in the normal (and only) way:

global theGlobalVar

set theGlobalVar to "test"
display dialog getVar(theGlobalVar)

on getVar(aVar)
	return aVar
end getVar

Thanks for the answer, i’ve understood the concept of global variable

What i do not see is:

  • how it answers my request ("Would you know a way to achieve either: 1. … or 2. …) ?
  • what you meant by “For the second one you could do something like…”

I tried to explicitely make heritance possible, but it does not work either

global MyVar
global thisScript

set thisScript to me

set MyVar to "test"

getVarWithName("MyVar")

on getVarWithName(aString)
	set myScript to "get " & aString
	
	script myScript2
		property parent : thisScript
		run script myScript
	end script
	
	return (run script myScript2)
end getVarWithName

→ returns “Variable MyVar is undefined”

I have now idea what you mean with this. Just place global aVar in your script if you want to access the global variable.

I don’t think this is possible

See my PM
Thanks

Yahoo.
I found a way to do it (here http://macscripter.net/viewtopic.php?id=24559)

set var to {1, 2, 3, 4, 5}
evaluate("var") --> {1, 2, 3, 4, 5}

to evaluate(theThing)
	run script "on run {x}
return x's " & theThing & "
end" with parameters {me}
end evaluate

As a consequence i have found a solution for the above problem, i 'll post in code exchange

here it is :
http://macscripter.net/viewtopic.php?pid=127240