Script to write to script

Is it possible to have a script append text into another script? I tried a simple write from this code in another post.


set previous_ to read file "Shared G4 HD:Users:karrenmay:Desktop:imageNumberFile.txt"
set numberIm to previous_
set numberIm to ((numberIm) + 1)

my write_to_file("" & numberIm & "", "Shared G4 HD:Users:karrenmay:Desktop:imageNumberFile.txt", true)

on write_to_file(this_data, target_file, append_data)
   try
       set the target_file to the target_file as text
       set the open_target_file to �
           open for access file target_file with write permission
       if append_data is false then �
           set eof of the open_target_file to 0
       write this_data to the open_target_file --starting at eof
       close access the open_target_file
       return true
   on error
       try
           close access file target_file
       end try
       return false
   end try
end write_to_file

but it messed up the script since it treated it as text. I guess I’ll have to call Script Editor to do the work but I wanted it to happen in the background.

My goal, and this may not work, is to save a script as an application bundle, then put a copy of the app bundle inside of the original bundle then when the script runs I’ll have it collect data from the user, append the second apps “main.scpt” with the variables then copy the app bundle to the desktop and rename it. Does this sound possible?

Software making software! Oh My!

Thanks,
Mark

I haven’t appended code to an existing script, but I have scripted Script Editor. Here is an application I have to save a copy of a script as a Run Only version so I can give the scripts out without people messing with them. Maybe some of this code will get you part of the way there. Check the Script Editor dictionary to see what commands are available to add text/code to an open script.

on open these_items
	set PathToDesktop to path to the desktop as text
	tell application "Script Editor"
		launch
	end tell
	tell application "Finder"
		activate
		if not (exists folder "Scripts RUN ONLY Copy") then
			make new folder at desktop with properties {name:"Scripts RUN ONLY Copy"}
		end if
	end tell
	repeat with i from 1 to the count of these_items
		set this_item to (item i of these_items)
		set the item_info to info for this_item
		tell application "System Events"
			if (alias of the item_info is true) then
				tell me
					activate
					display dialog "No aliases, AppleScript files only." buttons "Cancel"
				end tell
			end if
			if (kind of item_info is "script") then
				set ScriptKind to "script"
			else
				if (kind of item_info starts with "Application") then
					set ScriptKind to "application"
				else
					tell me
						activate
						display dialog "This is not an AppleScript." buttons "Cancel"
					end tell
				end if
			end if
		end tell
		tell application "Script Editor"
			activate
			try
				open this_item
			on error
				display dialog "Could not process. This may not be an AppleScript. Skipping this file."
			end try
			set ScriptName to name of front document
			save front document in (PathToDesktop & "Scripts RUN ONLY Copy:" & ScriptName) as ScriptKind with run only without startup screen and stay open
			close front document
		end tell
	end repeat
	tell application "Finder"
		activate
		try
			open folder "Scripts RUN ONLY Copy"
		end try
	end tell
end open

Browser: Safari 419.3
Operating System: Mac OS X (10.4)

Thanks for the reply. I’ll look through it shortly. :smiley:

I’ve been playing with something like this ( see here ) for a little while. The idea is to put the script to be made in between comment tags. (* *)
And Inside the tags wrap the script with a second set of tags: Script_Start_Point and Script_End_point

Then use AppleScript’s delimiters to get the text in between.
The rest of the script saves the result as an App.

This has worked great for me.

Here is a new incarnation.
The old on had to be run from the Original script open in Script Editor.
This one can be saved as an Application bundle.
The script reads the main.scpt file in the contents of the bundle using the Unix command Cat.

And then the same AppleScript’s delimiters as before chop it up into the script.
The result at the moment is still opened in S.E an then saved as a app it self.
I have only just rewrote it so it will most likely get cleaned up soon.

property bugcheck : false
on run
	-- Gather Info
	
	display dialog "What is You Name" default answer "" buttons {"Cancel", "Ok"} default button 2
	copy the result as list to {text_returned, button_pressed}
	if button_pressed is "Ok" then
		set getName to "Property yourName : \" " & text_returned & "\"" & return
		my maker(getName)
	end if
end run

on maker(getName)
	-- Read the main.scpt
	if bugcheck then say "1"
	tell application "Finder"
		set Pathz to ((path to me) & "Contents:Resources:Scripts:main.scpt" as string)
		set Pathz to POSIX path of Pathz
		set thecat to do shell script "cat " & "\"" & Pathz & "\"" & " "
		set AppleScript's text item delimiters to "Script_Start_Point"
		set thecat to text item -1 of thecat -- this works from bottom of text to first break point  "Script_Start_Point"
		set AppleScript's text item delimiters to "Script_End_point"
		set script_text to text item 1 of thecat
		set AppleScript's text item delimiters to ""
	end tell
	if bugcheck then say "2"
	set file_path to (path to desktop as Unicode text) & "SayIt_Test.app"
	if bugcheck then say "set desktop"
	-- add the two parts of the script
	set script_text to getName & script_text
	-- use "Script Editor" to make the app
	my RunMaker(script_text, bugcheck, file_path)
	
end maker
on RunMaker(script_text, bugcheck, file_path)
	set appname to "Script Editor" -- My S.E kept loosing the app name below for some od reason..? so I put this in until I reboot
	tell application appname
		activate
		if bugcheck then say "activate"
		make document with properties {text:script_text}
		if bugcheck then say "make"
		save document 1 as "application bundle" in file file_path with stay open without startup screen
		if bugcheck then say "save"
		close document 1
	end tell
	
end RunMaker
-- paste script to be installed as an .app between the  "(* Script_Start_Point"  and  "Script_End_point  *)"
-- example below

(*

 -- >Script_Start_Point
display dialog "Tell me What to say" default answer " Hello " & yourname buttons {"Cancel", "Say it"} default button 1
copy the result as list to {text_returned, button_pressed}
if button_pressed is "Say it" then
	say text_returned
end if

Script_End_point< --- 
*)

*Edit *Ah … Forgot to mention in this script (above) when run it asks the user for info. This is then added to the script when Saved.

Hi,

Here’s an example of how you might add text to a compiled script and create a new script. Suppose there is a compiled script on the desktop:

property someprop : "hello"
--
display dialog someprop
display dialog addedprop

The user chooses that script when the next script is run:


set f to choose file
set S to load script f
set S_text to S as text
set new_text to "MakeScript()
on MakeScript()
script
property addedprop: \"bye\"
" & S_text & return & "end script
end MakeScript"
set new_s to run script new_text
set file_spec to ((path to desktop as string) & "new.scpt") as file specification
store script new_s in file_spec
run script file_spec

The run script at the end, only shows that the script works.

If you’re using AS Studio, it might be better to just store your user specific info in the user defaults.

gl,

Wow… I did not know this existed, but I was wondering if Osascript could save the file without opening S.E.
So while looking at the man page I came across the Osacomplie.
And it works :slight_smile:

So Now the script below when saved as a Bundled app. will not need to open Script editor and will:

Ask the user for some info.
It will read the template script in its own main.scpt ( held between the tags (see above post)
Splice the two as one.
Write out the complied script as a app in this case on your desktop.

property bugcheck : false
on run
	-- Gather Info
	display dialog "What is You Name" default answer "" buttons {"Cancel", "Ok"} default button 2
	copy the result as list to {text_returned, button_pressed}
	if button_pressed is "Ok" then
		set getName to "Property yourName : \" " & text_returned & "\"" & return
		my maker(getName)
	end if
end run

on maker(getName)
	-- Read the main.scpt
	if bugcheck then say "1"
	tell application "Finder"
		--set Pathz to "Macintosh HD:Users:username:Documents:Script App Installertester.app:Contents:Resources:Scripts:main.scpt" as string -- for testing
		set Pathz to ((path to me) & "Contents:Resources:Scripts:main.scpt" as string)
		set Pathz to POSIX path of Pathz
		set thecat to do shell script "cat " & "\"" & Pathz & "\"" & " "
		set AppleScript's text item delimiters to "Script_Start_Point"
		set thecat to text item -1 of thecat -- this works from bottom of text to first break point  "Script_Start_Point"
		set AppleScript's text item delimiters to "Script_End_point"
		set script_text to text item 1 of thecat
		set AppleScript's text item delimiters to ""
	end tell
	if bugcheck then say "2"
	-- add the two parts of the script
	set script_text to getName & script_text
	if bugcheck then say "Added"
	-- use "Script Editor" to make the app
	my RunMaker(script_text, bugcheck)
	
end maker
on RunMaker(script_text, bugcheck)
	set file_path to (path to desktop as Unicode text) & "SayIt Test.app"
	set file_path to POSIX path of file_path as string
	do shell script "echo " & quoted form of script_text & "|osacompile  -o \"" & file_path & "\""
	if bugcheck then say "saved"
end RunMaker

-- paste script to be installed as an .app between the  "(* Script_Start_Point"  and  "Script_End_point  *)"
-- example below

(*

 -- >Script_Start_Point 
 display dialog "Tell me What to say" default answer " Hello " & yourname buttons {"Cancel", "Say it"} default button 1
copy the result as list to {text_returned, button_pressed}
if button_pressed is "Say it" then
	say text_returned
end if 
Script_End_point< --- 
*)

Hi Mark,

Why don’t you just use a constructor function to set the initial value of the property yourname? Then you use ‘store script’ to save the compiled script.

gl,

Might be worth mentioning that the script-to-text coercion is not vanilla, and requires Jon’s Commands, kel. :slight_smile:

That is very cool. It looks very close to what I need to do. I have been placing my script and properties in it but have hit a snag. I have about 15 different pieces of info I collect from the user (see below).


property processName : ""
property processQuality : ""
property processFormat : ""
property processProfile : ""
property processProfile2 : ""
property processScale : ""
property processRes : ""
property imageWidth : ""
property imageHeight : ""
property imagePercent : ""
property processSubFolder : ""
property processSubName : ""
property openAfter : ""
property processWatermark : ""
property processFileIcon : ""

So what is the best way to send them to the maker handler “on maker(getName)”?
Also, I wanted to use a custom icon and was thinking I could just copy it from the original bundle by replacing applet.icns in the original bundle then copy it over to the new app after it is created. Is there a better way to accomplish that?

Many Thanks,
Mark

Hi Kai,

I did not know that! All these years, I thought it was a built in coercion. Interesting. So this wouldn’t work with intel machines.

Thanks,

Hey Kel,

I wasn’t familiar with those. I’m fairly new to Applescript, although I’ve use Apple since System 7, most of the scripts I’ve made were pretty basic stuff. Just recently I’ve had need to get more advanced so I’ve learned a lot the last couple of months.

So with store script would it be possible to store the results of the first script as main.scpt in an existing bundle then copy the bundle to the desktop and rename it?

I modified mark hunte’s example, and it is very close, but I just wasn’t sure of how to pass 15 variables instead of just 1. Will a handler accept something like:

on myHandler(input1, input2, etc.)

I’ll research your suggestions further. Thanks for the input.

Mark

I think what Kel means is the app that gets written out should have a function to get the User input the first time its Run.
Doing that will make you life much easier.

This is the install app. as you see it just installs the second app.

The second app has the function to get the user input the first time around and then use it on further launches.
It does this by using a true and false property
There is room for you to expand on it, I.E have a reset button.
( I do this at work. where I have a script that sets up windows positions for my staff. These have to be just so.
The is a “Reapply” button and a “Save” button. If “Reapply” is clicked the script will set the windows up.
If “Save” is clicked it will Save the current window positions, but only if you enter the correct code first.
)

property bugcheck : false
on run
	
	my maker()
	
end run

on maker()
	-- Read the main.scpt
	if bugcheck then say "1"
	tell application "Finder"
		--set Pathz to "Macintosh HD:Users:username:Documents:Script App Installertester.app:Contents:Resources:Scripts:main.scpt" as string -- for testing
		set Pathz to ((path to me) & "Contents:Resources:Scripts:main.scpt" as string)
		set Pathz to POSIX path of Pathz
		set thecat to do shell script "cat " & "\"" & Pathz & "\"" & " "
		set AppleScript's text item delimiters to "Script_Start_Point"
		set thecat to text item -1 of thecat -- this works from bottom of text to first break point  "Script_Start_Point"
		set AppleScript's text item delimiters to "Script_End_point"
		set script_text to text item 1 of thecat
		set AppleScript's text item delimiters to ""
	end tell
	if bugcheck then say "2"
	
	if bugcheck then say "Added"
	-- use "Script Editor" to make the app
	my RunMaker(script_text, bugcheck)
	
end maker
on RunMaker(script_text, bugcheck)
	set file_path to (path to desktop as Unicode text) & "MyProperties.app"
	set file_path to POSIX path of file_path as string
	do shell script "echo " & quoted form of script_text & "|osacompile  -o \"" & file_path & "\""
	if bugcheck then say "saved"
end RunMaker

-- paste script to be installed as an .app between the  "(* Script_Start_Point"  and  "Script_End_point  *)"
-- example below

(*

 -- >Script_Start_Point 
 global theProperties
property processName : {"processName", "Name", ""}
property processQuality : {"processQuality", "Quality", ""}
property processFormat : {"processFormat", "Format", ""}
property processProfile : {"processProfile", "Profile", ""}
property processProfile2 : {"processProfile2", "Profile2", ""}
property processScale : {"processScale", "Scale", ""}
property processRes : {"processRes ", "Res", ""}
property imageWidth : {"imageWidth", "Width", ""}
property imageHeight : {"imageHeight", "Height", ""}
property imagePercent : {"imagePercent", "Percent", ""}
property processSubFolder : {"processSubFolder", "SubFolder ", ""}
property processSubName : {"processSubName", "SubName", ""}
property openAfter : {"openAfter", "After ", ""}
property processWatermark : {"processWatermark", "Watermark", ""}
property processFileIcon : {"processFileIcon", "FileIcon", ""}
property firstRun : true
on run
	-- Gather Info
	if firstRun is true then
		
		set theProperties to {processName, processQuality, processFormat, processProfile, processProfile2, processScale, processRes, imageWidth, imageHeight, imagePercent, processSubFolder, processSubName, openAfter, processWatermark, processFileIcon}
		
		repeat with i from 1 to number of items in theProperties
			set this_item to item i of theProperties
			
			display dialog "Enter : " & item 2 of this_item default answer "" buttons {"Cancel", "Next"} default button 2
			copy the result as list to {text_returned, button_pressed}
			set item 3 of this_item to "The Property " & item 3 of this_item & " is :" & text_returned & return as string
			
			if button_pressed is "Next" and this_item is processFileIcon then
				set firstRun to false
				my appz()
				
				exit repeat
				
			else if button_pressed is "Next" then
				
			end if
			
		end repeat
	else
		my appz()
	end if
	
end run


on appz()
	set biglist to ""
	theProperties
	repeat with i from 1 to number of items in theProperties
		set this_item to item i of theProperties
		set biglist to biglist & item 3 of this_item as string
	end repeat
	display dialog biglist buttons {"Cancel", "Ok"} default button 2
end appz
Script_End_point< --- 
*)

Hi Mark,

Actually, I meant after the user info is collected, use a constructor function to set initial values for the compiled script. I don’t know how the other Mark is getting the info. Something like this:


set S to MakeScript({"hello", "bye"})
set file_spec to ((path to desktop as string) & "my.scpt") as file specification
store script S in file_spec
run script file_spec
--
on MakeScript(p)
	set {x, y} to p
	script
		property prompt1 : x
		property prompt2 : y
		--
		display dialog prompt1 & return & prompt2
	end script
end MakeScript

The stored script “my.scpt” will look like this:

property prompt1 : x
property prompt2 : y

display dialog prompt1 & return & prompt2

and the values of x and y are stored in the script’s memory. The ‘run script’ shows that it works.

I still think that the best way to do this is to create and read a plist file. Each user would have their own preferences instead of messing around with the application bundle.

gl,

Hi Kel, thanks for you help on this subject.
I have learnt in the process many ways to write-out an app from a script.

one thing I noticed is that if you use store script and give the file a .app extension, there is no way to save it as a Stay open app. Is this right??

If so I have an idea which I have tested and works, but I foresee an issue with it which may involve null characters (only posting it will tell me)

Thanks

Hello.

I just want to add that Matt-Boy’s excellent save as run only applet script in post #2 now need to address AppleScript Editor instead of Script Editor.

This applet provides as security for not your last source getting eaten up (disappear forever) :D. Highly recommended when you want to save something as run only! :slight_smile:

Here is a small script runner to test your read only script with, just drop your run only on this
script when the script below is saved as an applet.


on open these_items
	set this_item to item 1 of these_items
	try
		run script this_item
	on error e number n
		tell me
			activate
			display dialog "error running script file" & e & " : " & n
		end tell
	end try
end open