Saving a variable's name as text

I’m trying to set up some application preferences subroutines using the shell script “defaults” system. As far as I can work out I can only pass text as a variables value (No lists or records unfortunately) - Please put me right if I’ve got this wrong! So, rather than hardcoding the preferences I hink I’m going to use into the subroutines I’d like to figure out how to pass a list of variables and have the subroutine call the default key by the name of the variable and then set the value of the default as the value of the variable. In short, is there any way to turn the name of a variable ( thisVariable ) into text (“thisVariable”)???:confused:

Hi Matt,

Many times when people post about coercing labels of variables to string and vice versa, there are better ways to approach your goal.

Through out these years I have never seen a case where coercing string to variable label has ever brought efficiency.

You should post what you are trying to do. From there, they might post efficient code.

gl,

This needs a lot of work and will break if you use anything even slightly exotic like lists of lists or records with values other than integers, reals, or strings but for a basic app, it should suffice. (Please, if you wish to further the discussion of the “safety” of using “run script” to coerce values to records, etc., please add it to thread 13178; I also think we’ve covered the “snr” discussion in other threads and it probably doesn’t need to be rehashed here.)

--set the defaults for your app here; note: your default names have to include the class type as the last part for this to work but the beginning can be anything (e.g., user_name_string, current_date, update_log_bool, etc.):
property default_1_string : "string data"
property default_2_int : 100
property default_3_real : 3.14159
property default_4_bool : false
property default_5_date : (current date)
property default_6_list : {1, 2, 3, "a", "b", "c"}
property default_7_record : {rec_val_1:1, rec_val_2:"b", rec_val_3:3}

property my_app_identifier : "com.generic.myapp" --update this to something unique for your app
property the_plist : missing value

--when you launch, read the defaults:
my read_all_defaults()
--you may need to post process records and lists to convert values to the proper class after reading a default; integers, reals, & strings work the best

--this is just a test to see that we read the defaults:
get {default_1_string, default_2_int, default_3_real, default_4_bool, default_5_date, default_6_list, default_7_record}
-->{"string data", 100, 3.14159, false, date "Monday, July 11, 2005 2:25:49 PM", {1, 2, 3, "a", "b", "c"}, {rec_val_1:1, rec_val_2:"b", rec_val_3:3}}

--when you quit, write the defaults:
my write_all_defaults()


--******** Default Routines *******-- 

on write_all_defaults()
	set the_defaults to {default_1_string, default_2_int, default_3_real, default_4_bool, default_5_date, default_6_list, default_7_record}
	set default_names to {"default_1_string", "default_2_int", "default_3_real", "default_4_bool", "default_5_date", "default_6_list", "default_7_record"}
	repeat with i from 1 to (count default_names)
		my write_default(item i of default_names, item i of the_defaults, the_plist)
	end repeat
end write_all_defaults

on read_all_defaults()
	set the_plist to (path to preferences folder as Unicode text) & my_app_identifier --leave off the ".plist" extension
	set the_defaults to {}
	set the_defaults_old to {default_1_string, default_2_int, default_3_real, default_4_bool, default_5_date, default_6_list, default_7_record}
	set default_names to {"default_1_string", "default_2_int", "default_3_real", "default_4_bool", "default_5_date", "default_6_list", "default_7_record"}
	repeat with i from 1 to (count default_names)
		try
			set end of the_defaults to my read_default(item i of default_names, the_plist)
		on error --initialize the pref if it doesn't already exist:
			my write_default(item i of default_names, item i of the_defaults_old, the_plist)
			set end of the_defaults to item i of the_defaults_old
		end try
	end repeat
	set {default_1_string, default_2_int, default_3_real, default_4_bool, default_5_date, default_6_list, default_7_record} to the_defaults
end read_all_defaults

on write_default(the_default, the_value, the_plist)
	set default_class to my get_default_class(the_value)
	if default_class = "string" then
		set the_value to quoted form of the_value
	else if default_class = "date" then
		set the_value to quoted form of (the_value as Unicode text)
	else if default_class = "array" then
		set the_value to my get_list_string(the_value)
	else if default_class = "dict" then
		set the_value to my get_record_string(the_value)
	end if
	do shell script "defaults write " & quoted form of POSIX path of the_plist & " " & quoted form of the_default & " -" & default_class & " " & the_value
end write_default

on read_default(the_default, the_plist)
	set the_value to (do shell script "defaults read " & quoted form of POSIX path of the_plist & " " & quoted form of the_default)
	return my get_default_as_class(the_default, the_value)
end read_default

on get_default_class(the_default)
	set the_class to the_default's class
	if the_class is in {string, Unicode text} then
		return "string"
	else if the_class = integer then
		return "int"
	else if the_class = real then
		return "float"
	else if the_class = boolean then
		return "bool"
	else if the_class = date then
		return "date"
	else if the_class = list then
		return "array"
	else if the_class = record then
		return "dict"
	end if
end get_default_class

on get_default_as_class(the_default, the_value)
	set the_class to the_default's word -1
	if the_class = "string" then
		set the_class to "Unicode Text"
		set the_value to "\"" & the_value & "\""
	else if the_class = "int" then
		set the_class to "integer"
	else if the_class = "bool" then
		set the_class to "boolean"
	else if the_class = "date" then
		return my get_date(the_value)
	else if the_class = "list" then
		return my get_list(the_value)
	else if the_class = "record" then
		return my get_record(the_value)
	end if
	run script (the_value & " as " & the_class)
end get_default_as_class

on get_date(the_value)
	set the_GMT_operator to the_value's character -5
	if the_GMT_operator = "-" then
		set the_GMT_operator to -100
	else
		set the_GMT_operator to 100
	end if
	set {the_year, the_month, the_day, the_hour, the_minute, the_second, the_GMT} to the_value's words
	set the_GMT to ((the_GMT as integer) / the_GMT_operator)
	set the_date to my snr(my get_date_format(), "YYYY", the_year)
	set the_date to my snr(the_date, "MM", the_month)
	set the_date to my snr(the_date, "DD", the_day)
	set the_date to the_date & " " & the_hour & ":" & the_minute & ":" & the_second
	set the_date to date the_date
	if not (((time to GMT) / hours) = the_GMT) then set the_date to the_date + ((the_GMT * hours) - (time to GMT))
	return the_date
end get_date

property date_formats : {"MM/DD/YYYY", "DD/MM/YYYY", "YYYY/MM/DD", "YYYY/DD/MM"}
property test_dates : {"12/21/2002", "21/12/2002", "2002/12/21", "2002/21/12"}

on get_date_format()
	repeat with i from 1 to (count of test_dates)
		try
			get (date (item i of test_dates))
			return (item i of date_formats)
		end try
	end repeat
	return "Could not determine date format."
end get_date_format

on get_list(the_value)
	set the_value to my string_to_list(the_value's text 2 thru -2, ", ") --unfortunately, this converts everything to strings
	--this allows integers & reals:
	repeat with i from 1 to (count the_value)
		set this_value to item i of the_value
		try
			set this_value to this_value as real
		end try
		if this_value's class = real and (this_value as Unicode text) ends with ".0" then set this_value to this_value as integer
		set item i of the_value to this_value
	end repeat
	return the_value
end get_list

on get_list_string(the_value) --this will break if your list contains a string value with a comma (or a date)
	try
		get the_value as integer
	on error e
		set the_value to e's text 13 thru -21
	end try
	return my snr(the_value, ",", "")
end get_list_string

on get_record(the_value)
	set the_value to my string_to_list(the_value's text 2 thru -4, "; ")
	set the_value_count to (count the_value)
	set the_record to {}
	repeat with i from 1 to the_value_count
		set this_item to item i of the_value
		set this_item to my string_to_list(this_item, " = ")
		set the_label to this_item's item 1's text 2 thru -2
		set this_value to my list_to_string(this_item's items 2 thru -1, " = ")
		try
			set the_record to the_record & (run script "{" & the_label & ":" & this_value & "}")
		on error
			set the_record to the_record & (run script "{" & the_label & ":\"" & this_value & "\"}")
		end try
	end repeat
	return the_record
end get_record

on get_record_string(the_value) --this will break if your record contains a string value with a comma (or a date)
	try
		get the_value as integer
	on error e
		set the_value to e's text 13 thru -21
	end try
	set the_value to my string_to_list(the_value, ", ")
	set the_value_count to (count the_value)
	repeat with i from 1 to the_value_count
		set this_item to item i of the_value
		set this_item to my string_to_list(this_item, ":")
		set the_label to this_item's item 1
		set this_value to my list_to_string(this_item's items 2 thru -1, ":")
		if i < the_value_count then set this_value to this_value & " "
		set item i of the_value to (the_label & " " & this_value)
	end repeat
	return the_value as Unicode text
end get_record_string

on snr(the_string, search_string, replace_string)
	tell (a reference to my text item delimiters)
		set {old_tid, contents} to {contents, search_string}
		set {the_string, contents} to {the_string's text items, replace_string}
		set {the_string, contents} to {the_string as Unicode text, old_tid}
	end tell
	return the_string
end snr

on list_to_string(the_list, the_delim)
	tell (a reference to my text item delimiters)
		set {old_tid, contents} to {contents, the_delim}
		set {the_list, contents} to {the_list as Unicode text, old_tid}
	end tell
	return the_list
end list_to_string

on string_to_list(the_string, the_delim)
	tell (a reference to my text item delimiters)
		set {old_tid, contents} to {contents, the_delim}
		set {the_string, contents} to {the_string's text items, old_tid}
	end tell
	return the_string
end string_to_list

Jon

Thanks Jon
You are, as we say in London, a Diamond Geezer!