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”)???
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!