Put recurring block of code into variable

Hey,

I have a block of code that recurs throughout my applescript. In the interest of clarity and efficientcy I was wondering if there is a way to put the set of commands into one variable and just call the variable. I would have thought that would be easy to do but I’ve been searching for quite some time and couldn’t come up with it…Thanks for any help

You need a “handler”. Here’s a 3-part tutorial for them…
http://macscripter.net/articles/417_0_10_0_C/
http://macscripter.net/articles/427_0_10_0_C/
http://macscripter.net/articles/433_0_10_0_C/

Thanks Regulus… very helpful :slight_smile:

These links no longer work is there a good article on reference a large block of code over and over again in a script? The “set” command is only for small stuff it seems.

Here are the working links to the articles

Getting Started with Handlers (Part 1 of 3)
Getting Started with Handlers (Part 2 of 3)
Getting Started with Handlers (Part 3 of 3)

Thank you :slight_smile:

You can call blocks of code by calling the handler


on run{}
display dialog my md5create("Hello World!")
end run

on md5create(stringtohash)
	set hashedBoxcarUSER to item 2 of stringtolist((do shell script "md5 -s \"" & stringtohash & "\""), " = ")
	return hashedBoxcarUSER
end md5create

on stringtolist(theString, delim)
	set oldelim to AppleScript's text item delimiters
	set AppleScript's text item delimiters to delim
	set dlist to (every text item of theString)
	set AppleScript's text item delimiters to oldelim
	return dlist
end stringtolist

Hello Oscar.

Nice collection of script you got in CodeExchange! :slight_smile:

You can also use script objects to create blocks of code, and thereby create several almost identical blocks of code, but have deviating variable values within them. This is called a closure, and is more or less the same as a code block - block in Objective-C, though changing the parameters in a closure is a little bit more awkward.

property clause : ""

script closure
	on run
		run script clause
	end run
end script
set clause to "tell application \"Finder\" to activate "
set instance to closure
run instance
set clause to "tell application \"Safari\" to activate "

run instance
set nextInstance to closure
run nextInstance

I also think this is a parallell to, or can be used as way to implement the “fly-weight” pattern in Applescript: instead of having many similiar objects, you can resort to just have one, configurable one.

Very nice thanks, you guys are way more advanced than me!

Ok, here is a more practical yet contrived example, as it has to do more than just setting text item delimiters to be feasible to use this. Observe that the values I use for configuration are properties, and that I just run the script, not run script.

property oldTids : ""
property tids : ""

on makeDelimScript()
	script tiDelims
		set {oldTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, tids}
	end script
end makeDelimScript

# I create and configure the first text item delimiter script.
set tids to ":"
set colonTids to makeDelimScript()
run colonTids

set mpath to "A:long:path:of:type:hfs"
run colonTids
set those to text items of mpath
log those
-- > (*A, long, path, of, type, hfs*)
# I create and configure the second text item delimiter script.
set tids to oldTids
set oldDelims to makeDelimScript()
run oldDelims
set these to text items of mpath
log these
--> (*A, :, l, o, n, g, :, p, a, t, h, :, o, f, :, t, y, p, e, :, h, f, s*)

# now I can use the two different Text item delimiter script instances
# at my leisure throughout a long script.


This is just an example for illustration, in real life you wouldn’t set text delimiters like this, because what is old text item delimiters, is really dependent of how many times you run each of the closures.

Here is a little bit more practical example, for exploding paths, now I have introduced a handler into the script, that returns the text items of the delimiters, not much gain, but it is going in the right direction! :stuck_out_tongue:

property tids : ""
global oldTids
on makeExplodePathScript()
	script explodepath
		to doit(aPath)
			local tmpvar
			set AppleScript's text item delimiters to tids
			set tmpvar to text items of aPath
			set AppleScript's text item delimiters to oldTids
			return tmpvar
		end doit
	end script
end makeExplodePathScript

set oldTids to AppleScript's text item delimiters
# I create and configure the first text item delimiter script.
set tids to ":"
set explodeHfsPath to makeExplodePathScript()

set mpath to "A:long:path:of:type:hfs"
set those to explodeHfsPath's doit(mpath)
log those
-- > (*A, long, path, of, type, hfs*)
# I create and configure the second text item delimiter script.
set tids to oldTids
set explodeToChars to makeExplodePathScript()
set these to explodeToChars's doit(mpath)
log these
--> (*A, :, l, o, n, g, :, p, a, t, h, :, o, f, :, t, y, p, e, :, h, f, s*)

set apxpath to "/A/deep/path/to/some/file/in/Contents/Resources/somewhere"
set tids to "/"
set explodePxPath to makeExplodePathScript()
set them to explodePxPath's doit(apxpath)
log them
--> (*, A, deep, path, to, some, file, in, Contents, Resources, somewhere*)
set andThose to explodeToChars's doit(apxpath)
# now when we are reusing, we are getting the gain, just one line now!
log andThose
--> (*/, A, /, d, e, e, p, /, p, a, t, h, /, t, o, /, s, o, m, e, /, f, i, l, e, /, i, n, /, C, o, n, t, e, n, t, s, /, R, e, s, o, u, r, c, e, s, /, s, o, m, e, w, h, e, r, e*)


Hello.

I really couldn’t make a closure take a parameter, and plagiate a code block in Objective-C.

However, I made a nice little handler for getting text items, because those two or three lines, has “bugged” me for a while now.

You specify the text item delimiter, what kinds of text items you want back, 0 is all - explosion, a list is returned you may specify −2 for instance to get the name of the parent folder, or {1,-2} to get the path of the parent folder. in cases where you don’t specify 0, you’ll get a piece of text back, reassembled with the text item delimiter

to explodeStuff(newtids, titems, theText, replaceDelim)
	local oldTids
	set {oldTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, newtids}
	if titems = 0 then
		set tmpvar to text items of theText
	else if class of titems = list then
		set tmpvar to text items (item 1 of titems as integer) thru (item 2 of titems as integer) of theText
		if replaceDelim is not null then
			set AppleScript's text item delimiters to replaceDelim
		end if
		set tmpvar to tmpvar as text
	else
		set tmpvar to text item titems of theText
	end if
	set AppleScript's text item delimiters to oldTids
	return tmpvar
end explodeStuff

set mpath to "A:long:path:of:type:hfs"
explodeStuff(":", 0, mpath, null)
log result
--> (*A, long, path, of, type, hfs*)

explodeStuff(":", -2, mpath, null)
log result
--> (*type*)

explodeStuff(":", {1, -2}, mpath, null)
log result
--> (*A:long:path:of:type*)

explodeStuff(":", {2, -2}, mpath, "/")
log "/" & result & "/posix"
--> (*/long/path/of/type/posix*)

(And I had to coerce the list items to integer to work.)

Edit
I added an extraparameter so that you can change the text item delimiter, when returning a range of text items.

--http://macscripter.net/viewtopic.php?pid=164575#p164575
(*
	Copyright © McUsr 2013 and put into Public Domain.
	You may not post this stand-alone somewhere.
	But you are free to use it and publish it with your
   own scripts , as long as the this notice remain.
  	No warranties about what so ever. 
	
	textItems : a handler for text item chores:
	Get a single item, all or a  range of item as list or 
	as text with new delimiter, or a count of items.
	
	Or convert a list to text, using a delimiter:
	*splitDelims* must then be null, and *replaceDelim* not null.
		
	General behaviour (get text items from text)
	Returns  *whatItems* text items of *theText* by *splitDelims*
	
	whatItems can be a range in the form of a list ({1,-3}), or an 
	integer denoting a single text item, or a list of all text items
	if whatItems = 0. If *whatItems* = null, then we return the count
	 of the items.

	if *replaceDelim* is not null, then it assembles *whatItems* of 
	the text	with it, and returns the result, as text.

	*)
to textItems(whatItems, theText, splitDelims, replaceDelim)
	local oldDelims, theExtract, theNewText
	
	if splitDelims = null and replaceDelim is not null then
		-- we are going to create a list of the text
		set {oldDelims, AppleScript's text item delimiters} to {AppleScript's text item delimiters, replaceDelim}
		set theExtract to theText as text
	else
		set {oldDelims, AppleScript's text item delimiters} to {AppleScript's text item delimiters, splitDelims}
		
		if class of whatItems = list then -- range
			set theExtract to text items (item 1 of whatItems as integer) thru (item 2 of whatItems as integer) of theText
			
			if replaceDelim is not null then -- swap delimiters
				set AppleScript's text item delimiters to replaceDelim
				set theExtract to theExtract as text
			end if
			
		else if whatItems = null then -- preflight
			set theExtract to (count text items of theText)
			
		else if whatItems = 0 then -- explode
			set theExtract to text items of theText
			
			if replaceDelim is not null then -- swap delimiters
				set AppleScript's text item delimiters to replaceDelim
				set theExtract to theExtract as text
			end if
		else -- single text item
			set theExtract to text item whatItems of theText
		end if
	end if
	set AppleScript's text item delimiters to oldDelims
	
	return theExtract
	
end textItems

-- Tests:

set mpath to "A:long:path:of:type:hfs"
# explode: (string to list)
textItems(0, mpath, ":", null)
log result
--> (*A, long, path, of, type, hfs*)

# a single item
textItems(-2, mpath, ":", null)
log result
--> (*type*)

# a range of items
textItems({1, -2}, mpath, ":", null)
log result
--> (*A:long:path:of:type*)

# a range of items with swapped delimiters
textItems({2, -2}, mpath, ":", "/")
log "/" & result & "/posix"
--> (*/long/path/of/type/posix*)

# another range coerced to text, same delimiter
textItems({1, -4}, mpath, ":", ":")
log result
--> (*A:long:path*)

# preflight mode, for counting the items
textItems(null, mpath, ":", null)
log result
--> (*6*)

# swapping text item delimiter

textItems(0, mpath, ":", "/")
log result
--> (*A/long/path/of/type/hfs*)


set fruits to {"Apple", "Pear", "Pine Apple", "Avocado"}
textItems(0, fruits, null, return)
log result
-->(*Apple
-->Pear
-->Pine Apple
-->Avocado*)

I have added the behaviour of converting a list into text, when splitDelims is null, and replaceDelim is not null.
It will use replaceDelim to create the text.

I hope it is not just me, who like to have a primitive handler to take care of the text item delimiters. :slight_smile:

Thanks again for all the great posts, very useful information here for me to revisit!

Model: Mac Pro (Late 2013)
AppleScript: 2.11
Browser: Safari 605.1.15
Operating System: macOS 10.14