Use of AppleScript objects.

Got a question, which hopefully is silly and I’m just missing something. :slight_smile:

I create with the following:

use AppleScript
use framework "AppKit"
use framework "Foundation"
use framework "EventKit"
use scripting additions

on constructor()
	set EventStore to current application's EKEventStore's (alloc()'s initWithAccessToEntityTypes:(current application's EKEntityMaskEvent))
end constructor

and no issues. If I try to create a script class however:

use AppleScript
use framework "AppKit"
use framework "Foundation"
use framework "EventKit"
use scripting additions


on EventStore_class()
	script make_EventStore
		on constructor()
			set EventStore to current application's EKEventStore's (alloc()'s initWithAccessToEntityTypes:(current application's EKEntityMaskEvent))
		end constructor
	end script
	make_EventStore's constructor()
	return make_EventStore
end EventStore_class

then I get the error that EKEventStore does not understand the “alloc” message.

What I am trying to do is to pretty much create pieces that can then be script objects so that multiple instances can be created for them. Works great normally but seems to be having issues with using it in combination with AppleScriptObjC.

Any help, guidance appreciated.

If you go to www.macosxautomation.com/applescript/apps/explorer.html, in the box at the right it says “Click here to download some sample scripts.” One of the samples includes how to use script objects in ASObjC.

The key is to make your script object separately, then return a new script object that inherits from it.

Thanks Shane! Really helped me out and got it working. :slight_smile:

Hey Shane,

Thought it was working but it is not. I went back to the example “Script object example” and checked there and it seems to have the same issue.

Using the following in the calling script:

set aThing to theLib's smartThing:"   hello   "
tell aThing to trim()
tell aThing to makeCaps()
set bThing to theLib's smartThing:"   No hello   "
tell bThing to trim()
tell bThing to makeCaps()
log "A : " & aThing's returnThing()
log "B : " & bThing's returnThing()

It returns back:

NO HELLO
NO HELLO

whereas one would expect it to return back:

HELLO
NO HELLO

In other words, we’re not really creating an instance of the script object allowing us to use multiple instances each with their own values.

Any thoughts?

Hi ehendrix,

Your statement is not a script object. You need 'script" and “end script” around the statement. I t looks you’ve got it reversed.

gl,
kel

Yeah – I’ve been conned :frowning:

OK, try this:

use framework "Foundation" -- loads framework

script MyThing 
end script

on smartThing:aValue
	script
		property parent : MyThing
		property stringStore : missing value 
		
		on trim()
			set my stringStore to stringStore's stringByTrimmingCharactersInSet:(current application's NSCharacterSet's whitespaceAndNewlineCharacterSet())
		end trim
		
		on makeCaps()
			set my stringStore to stringStore's uppercaseString()
		end makeCaps
		
		on returnThing()
			return my stringStore as text
		end returnThing
		
	end script
	
	set aThing to the result
	set stringStore of aThing to current application's NSString's stringWithString:aValue
	return aThing
	
end smartThing:

Hey Shane, excellent. THANKS!!!

So I used your example and enhanced it a little bit to also show inheritance. Here is the AppleScriptOBJ Library:


-- Created 2013-12-13 16:42:53 -0700 by Hendrix, Erik
-- 
use AppleScript version "2.3"
use scripting additions
use framework "Foundation"

-- Dummy script that is the root parent to ensure AppleScriptOBJ calls function.
script MyScript
end script

-- This is the parent class, need to use () otherwise can not define it as a parent in another class.
on ParentSmartThing(aValue)
	-- Object script
	script ParentClass
		-- Parent HAS TO BE the dummy script so that all the Objective-C goodies work
		property parent : MyScript
		
		-- My variable to store data in
		property stringStore : missing value
		
		-- Constructor, jsut sets the value.
		on constructor:aValue
			set my stringStore to current application's NSString's stringWithString:aValue
		end constructor:
		
		-- handlers for our object
		on trim()
			set my stringStore to (my (stringStore's stringByTrimmingCharactersInSet:(current application's NSCharacterSet's whitespaceAndNewlineCharacterSet())))
		end trim
		
		-- for retrieving the string 
		on returnThing()
			return my stringStore as text
		end returnThing
	end script
	
	ParentClass's constructor:aValue
	
	return ParentClass
end ParentSmartThing


-- This is the Child class.
on ChildsmartThing(aValue)
	script ChildClass
		-- Defining our parent, now we can use the property and handlers set from the parent
		property parent : ParentSmartThing(aValue)
		
		-- This class does not have the handler trim(), hence any calls to trim go to the parent.
		
		-- Really would not have required this, but added to show as an example how to override a parent's method yet being able to call the same parent's method as well.
		on constructor:aValue
			continue constructor:aValue
		end constructor:
		
		--Example on how we can use the property defined in the parent class here.
		on makeCaps()
			set my stringStore to my stringStore's uppercaseString()
		end makeCaps
		
		on returnTrimmed()
			-- Example how we can call the parent's methods.
			my trim()
			return my returnThing()
		end returnTrimmed
		
	end script
	ChildClass's constructor:aValue
	
	return ChildClass
	
end ChildsmartThing

and here is the sample for the calling script. It creates 2 instances of the child class and 1 instance of the parent class. It shows the use of the different handlers and how each instance has it’s own values.


use theLib : script "^" -- required
use scripting additions


set instanceA to theLib's ChildsmartThing("   I am instance A   ")
instanceA's trim()
instanceA's makeCaps()

set instanceB to theLib's ChildsmartThing("   and I am the 2nd instance   ")
instanceB's makeCaps()

set instanceC to theLib's ParentSmartThing("   and I am the 3nd instance but can not do caps   ")
instanceC's trim()

log "instanceA : " & instanceA's returnThing()
log "instanceB : " & instanceB's returnTrimmed()
log "instanceC : " & instanceC's returnThing()

Hopefully other folk’s find this useful as well.

Very nice! It’s a pity about the need to use parentheses, in terms of adding terminology.

True, but in all honesty this is much cleaner then what was done before (and not working). :slight_smile:

Found another gotcha however, the class can NOT be ().

For example, following does not work:

script MyScript
end script

on ParentSmartThing()
	-- Object script
	script ParentClass
		-- Parent HAS TO BE the dummy script so that all the Objective-C goodies work
		property parent : MyScript

       .... coding here

       end script
end ParentSmartThing

on ChildsmartThing(aValue)
	script ChildClass
		-- Defining our parent, now we can use the property and handlers set from the parent
		property parent : ParentSmartThing()

       .... coding here

       end script
end ChildSmartThing

One then ends back up that the stuff from Objective-C is not recognized. The way around this would be:


property p_dummy : missing value
script MyScript
end script

on ParentSmartThing(p_dummy)
	-- Object script
	script ParentClass
		-- Parent HAS TO BE the dummy script so that all the Objective-C goodies work
		property parent : MyScript

       .... coding here

       end script
end ParentSmartThing

on ChildsmartThing(aValue)
	script ChildClass
		-- Defining our parent, now we can use the property and handlers set from the parent
		property parent : ParentSmartThing(p_dummy)

       .... coding here

       end script
end ChildSmartThing

Took me a while to figure this out as I had a class set like that and it did not want to work, yet everything looked good and the same to me. Except that I was not providing a parameter.

I suspect it has to be something that will not compile as a method call.