WWDC2003 Session 414

Transcript

Kind: captions Language: en good morning thank you for coming my name is John Comiskey I'm and an engineer in the applescript group I want to talk to you today about three things three things we're going to talk about designing a dictionary for a newer and existing application we spend most of our time on that we're also going to talk about implementing scriptable objects to bring that design to reality we're going to focus mostly on cocoa scripting that's what I do most of the time myself we're talk about a little bit about carbon at the end and we're also going to talk about developing tests for your script ability as you go along so you make sure that you don't back track or have any regressions designing a dictionary is the most important part of the entire operation once you've done that writing code is not as hard the thing that we really want to encourage you to do is to use an object model in your dictionary Apple script functions best when applications have an object model in their dictionary and why do you want to use an object model in your dictionary well I think you already know the reasons for that you use object oriented programming languages yourself you know the benefits of them you wouldn't go back to the old ways of doing things anyway what we want you to do is to let scripters have all those same advantages we want them to be able to reuse your objects you put you put time and effort into those objects if you give the script or the opportunity to leverage that that adds value helps you sell your product helps you make money which is why you're in this business scriptable applications are interoperable i like to say two plus two is five to scriptable applications can do things that neither one of them can do alone neither one of them can do while being worked by hand if you've got one or if you've got two or more scriptable applications they can be combined together into a super application that does something that no one of them can do alone script ability an object model for script ability offers your users flexibility when I talk to people about making their applications scriptable they often say well why would anybody want to do that and my answer is I don't know why and you don't know why either but your customer knows he knows what he wants to do he knows what problem he needs self if you give him powerful recombine about reusable object he can build a solution for himself and you might be surprised sometimes at what your own customers do with your products they can also create new functionality that's missing sooner or later you have to ship your product and you always have a cool new feature that's almost done but it isn't ready to go and so you have to leave it out that's always a disappointment but it's a reality of being in business applescript is the feature that you forgot your customers can take applescript and use it to create features that are missing from your application if you went to the applescript studio session yesterday you saw a demo of using Apple script studio to create plugins for the Xcode program for the Xcode environment and we were able to create a feature that's really nice to have but it's missing from Xcode maybe someday it'll be a native feature of Xcode but in the meanwhile you can use Apple script to write a plug in plug it into Xcode and get a cool new feature that wasn't there well there's several reasons why you want to use not an object-oriented language the biggest one an object model in your dictionary and the biggest one is that Apple scripting op the object-oriented language itself it's got all the cool things there in all the other object oriented languages and Carrington's data hiding all of those kinds of things but you only get those benefits if you use an object model Apple script is also an English like language you write simple declarative sentences with a verb acting on a direct object modified by one or more clauses but you only get that nice English like flow if you use an object model in your dictionary when you're writing an apple script you always use cell blocks at least to tell applications which you can also use tell blocks to shorten the apple event that you have to write if you've got a complex or deep containment hierarchy you can nest tell blocks and then the Apple events that you write inside those tell blocks are shorter and smaller easier to read easier to understand but this only works if you've got to containment you are key in your object model and as I mentioned before applications can interoperate there's synergy between applications they already share data what we're talking about inviting them into a workflow together you can create a workflow across several different programs from one vendor or several vendors that solve your problem your end-users problem and once you've got a workflow like that it can be wrapped up in an applescript studio application and become one of these super applications that i mentioned you could do something some kind of post-production job that has to be done over and over and over again doesn't require a lot of artistic expertise but it needs to be done and it needs to be done a lot that can be turned into an automated workflow while we're talking about this today we're going to be developing some regression tests for your own software those can be put together into a workflow so that a tester can just fire up a studio application run it come back later and find out what the results of the tests were but none of this works unless you use an object model in your dictionary so what is an object model um it's a lot easier to say what it's not this is the implementation of folder actions from system nine it's not an object model it's five different verbs and you can see pretty quickly what goes wrong here two of these are removed two of these verbs have removed and add in them you could have used make and delete which are already standard verbs in a standard suite you can also see that these these events have have things that ought to be objects just embedded right into the verb it takes away the flexibility and a recombination that end user can do when the verb and the object are sealed together into a single event like this and you'll also see that these a lot of these end with a preposition and you all know you should never end a sentence with a preposition again this takes away flexibility prepositional phrases in Apple script should be parameters and they should usually be optional parameters you shouldn't force the user to describe prepositional phrases weather he needs them or not so this is a this is a good example of a bad example in Panther we have done something about this all the old verbs for folder actions are still there and they still work and we actually still use them ourselves internally but we've also provided an object model for folder actions the first thing you notice is the rectangle got smaller that this is a you can express all the same operations in a smaller dictionary if it's an object model these two objects can do all the things that those five verbs did plus a lot more you get more for your money with an object model when you start to design your object model you should plan for a full implementation look into the future we know that you've got to ship something and you've got a limited amount of time to do that but your life is going to be better and easier a year from now if you plan an object model with room to grow map out as big an object hierarchy as you think is meaningful for your for your application decide now what things are going to be called in the future so that we don't run into the problem of all the good names have been taken and define as much functionality as possible everything that someone can do by hand with your program is very good candidate for script ability some high-powered operations that might not be suitable to be done by hand might might also be targets for script ability as well your scripting of implementation may in the end actually be more powerful than your duty presentation now you plan for the future you plan this huge object modeling now you don't have time to implement it all you're going to have to scale back for your first release and only do part of it when you decide what you are going to do it's important to include a minimal functional set enough objects and enough verbs to do at least one interesting operation something that some customers been bugging you about if you pick a set of objects that allows you to perform that function you know you've got a minimal functional set there's sometimes things in your application it's hard to think how you might use them through script ability there's complex interactions one example in network setup you've got an IP address and you've got a router address and they're not independent of each other if you change one you might have to change the other and you have to do it in a synchronous fashion it's not easy to see how you're going to do that with Apple script maybe the solution for release one is to just leave those properties read-only chances are you're using a DHCP server anyway you need to know what the IP address is but you don't need to change it if you make that read only the information is available the values therefore your user and you've skipped the complex problem until later when you have more time to think about it but even if you have a largely read-only implementation in your first relief you should always provide at least one powerful read write function that can actually do something in the instance of network setup that would be the location if the user can switch his location through script ability then he really has the power he needs to do whatever he wants he's got to sit down in advance create a number of configurations organize them into locations that are meaningful for him but once he's done that all he needs to do is change the location as he moves from city to city or from work to home or into a conference room or anywhere else you might go the standard suite has a number of verbs that cover almost everything you're ever going to want to do get and set are used on properties of your of your objects and exists count make and delete are pretty much implemented for you by coco scripting there's not a lot that you have to do if you create scriptable objects according to the pattern that Coco scripting expects these four verbs are just going to work so and then in a standard suite all that's left is six other verbs that act on objects things like print and save where you're going to really have to write some code yourself and quit to quit the entire application we think the thirteen verbs in the standard suite will cover most of what you're going to want to do and you should always try to use them first before you create a verb of your own if you use an object model along with the standard suite you get this multiple multiplicative effect if your object model has say three objects with a verge of ten properties each and they can all be gut geht and step that's 60 operations you can perform right there if those three objects also respond to the 10 other verbs that act on objects and remember four of those 10 are done for you that's another 30 operations that your application can perform plus one more quit so that's 91 things that your application can do and you hardly written any code at all at this point one thing we tell people not to do is to create a bunch of verbs you saw what happened with uh with folder actions we created a bunch of birds it worked it covered the problem that we needed solve but it was kind of a dead end it couldn't do anything more than that so we we discouraged the creating of a lot of verbs the temptation is there to do that to just take an existing API and expose it as a lot of apple script verbs but it doesn't give you the power than an object model does a procedural verb is one-dimensional it performs one operation on one data item and they're married together like they were in the example that we saw and you have to anticipate every need for folder actions it was pretty easy because we were defining what folder actions was going to do and we knew when we got to the end of those five verbs that we were finished if you have a bigger more complex application than that you'll never know when you're done you'll never know when you've gotten to the end of the list procedural verbs are also really ugly they defeat the english-like syntax of apple script and make ample scripts very choppy and hard to read I've got an example here of a folder action verb the way things used to work in system nine and it's clunky and not too particularly meaningful it's hard to tell what that verb is going to do and there's a lot for the scripture to learn I've seen dictionaries with two and three hundred verbs a lot of herbs to slog through looking for the one that you want and even when you get to the end of the list you don't know for sure if you missed it or it's not there it's a lot for the script to learn and hard to retain that information if you don't use an object model and you create a lot of verbs instead your application script ability is somewhat of a dead end the only way you can communicate with other applications is by the native data forms strings and numbers you can pass strings and numbers back and forth to other applications and that's about it if you have an object model and you pattern your object model after the existing object models of other applications you can interact on a higher plane instead of just sending numbers back and forth if you do need a verb go ahead and create it first you should look at the standard verbs and make sure there's nothing there that you can use but once you've decided that that's the case yeah it's okay to go ahead and make your own verbs they should be simple applications that you have the simple operations that your application performs on its own objects and the names of these verbs are going to come from probably buttons and menu items that you already have in your program now that doesn't mean you should take every button and every menu item and turn it into a verb but when you're trying to figure out what to call a verb if you call it the same thing you call it in your UI you should try to create verbs that can be reused on multiple objects that's what the standard suite is all about is it's it's 13 verbs that we think you can use everywhere um you should try to do the same thing when you create verbs of your own if you create a verb that only acts on one object or one kind of object um you're slipping back into that procedural verb problem that we do we talked about and one thing that you want in it you want verbs that can be reused in your application a good place to find them in to reuse verbs from other applications look at the script of elapsed from Apple and see what's there that you might already be able to use if you copy a verb or any other term from another application you can copy the human readable term and the four byte code bolt that's going to make your program interoperates better with other programs your your dictionary is scoped to your application and you won't end up in collisions with other applications what you also won't end up in synergy with the miser and you should definitely choose reusable parameters there's a lot of things in the standard dictionary little prepositional phrases that modify the verbs that are going to be of use to you anywhere there's one in there for naming the target file that you want to write to that can be reused there's there's others in there for a asked me if I should do something before I quit that might be useful to you reuse those parameters to and recombine them with your verbs in different ways when you decide whether or not you're going to make a verb you should choose carefully what it is you do um you should always use a property instead of a verb whenever you can now I've got a big X here next to enable script Tim that sounds real simple why don't I like that it's just verb object not even any modifiers what's wrong with that nothing on the face of it but what happens after that that's wrong if you have an enabled verb well now you need a disabled verb and even though you've got an enable verb and a disabled verb you still don't know whether this thing was enabled or not in the first place and that might actually be more important than being able to turn it on and off if you have instead of simple boolean property called enabled then you can use the get and set verbs to replace your enable and disable verbs and you can actually get what the setting is now and decide whether or not you even need to touch it so uh when you've got a simple boolean switch that can be turned on and off make it a property and use getting set should pry you supply verbs to objects rather than data on it you're slipping back into the procedural verbs if you apply your verbs to data if the parameter to a verb is always a string are always a number you're slipping back into the procedural verbs there are some exceptions to this though it's much more natural in the case of say a chat program that wants to be scriptable to say i want to send a message to a purse well messages and object strings are it's okay for them to sit in the direct parameter but you'll find that when you've got something like a string or a number sitting in the direct parameter you should also have the direct object you should also have an indirect object a prepositional phrase that begins with preposition two and that's a second object that also participates in this operation and it's the target that the first object is going to be fired at definitely avoid just exposing your raw internal API don't just take all of the commands and all the routines in your API and just turn them into verbs this is how you end up with a dictionary with two or three hundred verbs in it it leads to these clunky one-dimensional procedural verbs that we don't like how do I decide what I'm going to call these things where do I get the words that I'm going to use in my dictionary where do I where do I decide how do I decide what these things are and what they're called the best way to do this if you can if you've got an existing application and you've got users that have been bugging you for automation um interview one of them sit them down maybe sits facing away from them and have them describe to you what it is they're doing the what they'll do is they'll lead you through the steps that it takes for them to perform an operation by hand write down what they're saying that that's your apple script now it's not going to compile and it's not going to run you're going to have to change the wording so that it's fitting into the apple script form but that's not the most important part the most important part is you're going to have to pull out of that description the objects that the person is talking about and make those the scriptable objects in your dictionary use the same words that your customers are already using to describe these things and then they don't have to relearn your program for script ability they look in the scripting dictionary and they say oh I know what that is and they know what it is because you've got the word from them um so then you define you define in your dictionary those those objects and properties that the that the user says he needs to do his job and you only create new verbs when he's doing something that your program does and other programs don't do that if you don't have the opportunity to talk to a real live user about how he does his work maybe your company has technical writers and produces some nice documentation in those dot in those documents there is very often a tutorial or a sample session of a user sitting down using the program this is the same kind of information that came from the interview that that step by step tutorial of how to do something with the program again that could be an applescript you've got to massage the spin taxi to the applescript form but much more importantly you have to create the objects that the user is manipulating so that script ability will be as powerful and more so than the GUI so you define those objects and properties that that are in your documentation create new verbs if you have to now you don't have to have separate documentation for your scripting and for the rest of your program because whatever it's called in the documentation that's what it's called in the dictionary if if you don't have if you're out there by yourself and you don't have customers and she can sit down and interview on a frequent basis and you don't have a big tech writing organization you can look at your own object model we started out by saying you know what what's good about object models you use them yourself you're using one in your application look at it and abstract from Matt the objects and properties that your customers are most likely to need to do to do what it is they want to do but the most you take this approach the most important thing is humanizing the programmatic terms that you've used just reading your source code it's too techy it's too hard to understand you have to put this in a form than an end user is going to be able to understand you definitely don't want to expose absolutely everything that's in your program you've probably got a few main objects that represent the concepts at the end users trying to work with you've also probably got a bunch of helper objects that do interesting and important things that the customer doesn't need to know about those helper objects don't belong in your Apple script dictionary just the main conceptual objects deal when you're pulling terminology out of your application you've got to humanize it and one of the most important things is get rid of the inter caps use separate words with white space in between them instead also a good terminology and Apple script doesn't use a lot of capital letters you only want to use capital letters for acronyms and proper nouns the reason for this is Apple script is English like these terms show up in different places in the inn and an apple event and if you've got a capital letter in the middle of an apple event it looks funny it's that capital letters there because it's a product name it makes sense but if it's there because it's one of your verbs or one of your objects it's going to confuse people if you have boolean properties you might have the word is in your code leave that out is mean something in Apple script you don't want to make it part of your terminology and again only make new words if you really need them the last way that you can go about it is to look at your own it's your own GUI and extract an object model from that this one's tricky because you have a tent you might have a tendency to script the user interface and that's something you don't want to do there's a session tomorrow 311 well we're going to talk about scripting the user interface and try to convince you further that that's not what you want to do so don't just describe the little widgets that are on the screen and give the user the ability to poke at them conceptualize it figure out what it is that that widget represents maybe it's a property maybe it's an object give it a name and put it in your dictionary and don't just inventory everything again you'll end up with a long dictionary that's hard to find things conceptualize what are these things that I'm manipulating what is it that I'm trying to do with them what properties do they have that can be get and set when you form the terms themselves don't use articles like and leave those out they can be sprinkled in to your Apple script later they don't affect the way that the aplex Crypt execute but they can make it easier to read if you've embedded them in your terminology then it's hard for a person writing an apple script to ship to ship them and shuffle them to where they ought to belong also avoid personal pronouns like me and my again me and mine mean something in apple script you don't want to stick them in your terminology and again if you do need to define some verbs you're probably going to find the terminology for them on an existing button or an existing menu item somewhere in your program again don't expose everything not every menu item needs to become a verb and the menu items that do need to become a verb are already in the standard suite at least that's our opinion when you're mapping stuff off of the screen into your dictionary most of the stuff you're looking at is going to be properties of an object generally one window or one pain within a window is going to represent an object and everything inside that is going to be a property on when you when you map that to your dictionary you're going to need to pick data types for those the most important one here on this slide is radio buttons if you have a small finite set of things of values that a property can take on that should be expressed as an enumeration it makes your Apple scripts look nice makes them easier to read gives the and it gives the script or the notion that he can't set this value to just any old thing he's got a pic from this list some other UI widgets lead to more to richer relationships in your object model some pop-ups are just replacements for radio buttons and in that case they ought to be rendered in your dictionary as an enumeration just like the radio buttons were but other pop-ups actually represent an element relationship if you change a pop up at the top of your window and it changes the entire contents of the screen and now you're looking at a different set of data then that pop up really represents a element relationship and to go back to our example of network set up the location is a pop up in the you I but it actually represents a element relationship in the object model the same thing with scrolling list sometimes a list is just a list of strings and if that's all it is and then maybe that's what you should be passing back to your user this is a property the property is an array of strings um but that's not always the case sometimes the scrolling list actually represents an element relationship for instance in the finder you've got a scrolling list of files that you would want to render in your dictionary as an element relationship a relationship between two objects table views are a rich source of element relationships this is a simple spreadsheet um there's already a table view script a table view suite or a table sweet sorry defined in the standard headers it's got a table which contains rows and columns the intersection of a row and column is a cell and each cell can't can in turn be a container for an entirely new object hierarchy the contents of a cell in a spreadsheet might be a chart and the chart has an entire object hierarchy of its own so this is somewhat of a physical mapping from your screen to a dictionary if you do something like a spreadsheet where the user has the opportunity to put all different kinds of data in here and you don't know in advance what it's going to be a physical mapping like this might be appropriate if you if you do know a little bit about the data that's that's expressed in a table view then you can make an abstraction in this instance this is a page from a database program that that I wrote just as an experiment the object here the table itself represents a database each instead of calling each each line a row we're going to call it a record and instead of a row being divided into cells we're going to have field and the fields are going to have names which happen to be the same names as the columns this is one step up from the physical mapping the most interesting thing about this is that Jim Mora is one of the 20 winning in coaches in NFL history one step up from that as a conceptual mapping we really know what this is all about this tables for one purpose it's not it's a database but it's my database and I control what's in it this is a part of the folder action set up user interface that's going to be in Panther um here the container is the application itself nobody nobody owns this there isn't a table anymore there's just folder actions and the application has a bunch of them and every folder action has a name and a switch that says whether it's enabled or not the thing that's not showing here is there's another scrolling list right next to it where every folder action has a set of scripts attached to it and that's an element relationship so when you're designing your dictionary we definitely want you to use an object model it makes it makes your program fit in better with Apple script it makes your program fit in better with other scriptable applications Apple scripts to do let's you be part of a workflow let you be part of a super application only create new verbs when you have to use something in the standard suite if you can omit certain boro MIT certain words from your terminology that make a mess of things and don't use uppercase unless it's a proper noun of some kind go ahead and take things from other programs the reason scriptable the reason scriptable applications interact the way they do is because they use similar terminology this this allows you to interact with other programs at a level above just passing back numbers and strings lay out the entire future as far as you think you're ever going to be able to go and then implement what you can in the first release remembering to give you your script or at least one really interesting thing that he can do you have to write a sample script so you need at least one really interesting thing to do um now you've got your dictionary and you need to write some code um there's three cases that you can find yourself in if you're really lucky you're starting from scratch you're building a whole new application from the ground up you can do whatever you want um much more likely you've got an existing application and you you've been tasked with adding script ability to it you're going to have to keep what's there keep the GUI functionality and add scripting to it you need to do a little retrofitting the toughest situation is when you've got a big existing framework that is not itself scriptable and you don't have the opportunity to make it scriptable perhaps your application is cross-platform and you use a framework that makes being cross-platform real easy but it makes being scriptable real hard so the first case maximum freedom starting from scratch I can do anything I want except interview a user who is using the program because it doesn't exist yet so how do I do this how do I find how do I develop my terminology if the program itself doesn't even exist well if you're from a large corporation that has a powerful marketing department and they provide you with detailed specifications in advance um that information can be used to develop the object model for your Apple script dictionary that's not normally the case the situation i find myself in and I've got some direction I've got some goals but I don't have a lot of real specifications um you could use a competitive analysis which means steal from other programs look at how other programs do similar things how they implement their their script ability and while you might not copy it exactly well you might not be able or allowed to copy it exactly you can certainly get some concepts or how other people are doing the same thing however you define your decide on your object model you should subject it to significant review pass it to other engineers back to the marketers that give you your specifications any tech writers that are going to need to write the documentation and especially to your testers your testers know what they need to test and the things that they need to test are easier to test if they're in your Apple script dictionary um and at some point along the line in the development your program you're going to do some prototyping you're going to take some of your ideas and concepts and lay them out at least in static screen shots that are going to give people some idea of what the application is going to look like when it's done once you've done that prototyping then you can sit a user or maybe a marketing manager down in front of it and say take me through the steps that you would do that you would do to perform some function and now you can do the interview and when you're done you'll have an apple script dictionary which is an object model of the conceptual objects that your end user is going to be using whether they're scripting or using the GUI this can actually be a design document for your entire application you've got you've got a running start here of how the entire application should look regardless of scripting one of the things that I do to make my life easier is I implemented a scriptable base class it does a lot of the common functions this is this is the promise of object-oriented programming reusable code so my scripting is mostly done by this reusable base object it gives me consistent behavior across all my objects all the objects in a particular program are going to behave very much the same we won't get a lot of chattering between them that makes them hard to use together if your company develops a suite of applications and you have a scriptable base a base class this is going to give you consistent behavior across your application this is beginning to build the synergy now these applications can talk to each other they have similar object models they have similar ways of describing those object models they can pass things back and forth that are a level up from just strings and numbers and let's code is less bugs if you've got a base class that works you find you're spending very little time debugging it and that's great because then you can do other stuff Maya Maya scriptable base class is called elements because every object in scriptable application dictionary is an element of some other object the top-level objects are all elements of the application itself good scriptable object have names so I have a way to set and get the name of my object excuse me get some water thank you in some applications you may find that you want unique IDs for your objects databases especially the the objects will have persistent unique IDs unique IDs in applescript are guaranteed to be good for one launch of the application and in order to create a unique ID that's good for one launch of the application all you need is a serial number just never give the same number out to two different objects and you're okay there's a slight problem with that though if somewhere in the execution of a script that application quits and then relaunches it will start reusing those unique IDs if you've saved an object specifier in a script variable and it's still hanging around after the application has quit and relaunched it might now refer to a different object and that could be bad um one way to get around that is to choose a time stamp you can get the time stamp once when your application launches or every time somebody creates an object now even if your application quit and relaunch is it will never generate the same unique ID again if you need unique IDs for something like a database that need to persist across several applicable laws of the application and need to stay the same across several launches the application corefoundation provides something called a uuid and it's great it's got a time stamp in it so it has all the qualities of the time stamp it's got your Ethernet hardware address in it so it can even be differentiated from objects created on other machines and if the first part of it is a hash key which means if you stick it into a hash table or a binary tree the the IDs will spread out across the range and they won't cluster together like if you were just using a plain old time stamp every good scriptable object needs to be able to send back an object specifier to describe itself so that that same object can be retrieved later later in the script in my scriptable based class I'm implemented a cascade that creates an object specifier for every object and tries to create the best object specifier that it can if if unique ID is defined in the dictionary for this object I go ahead and use that unless of course there isn't one is if there is no unique ID defined in the in the dictionary then I look and see if name is defined in the dictionary every good Apple script scriptable object should have one or the other of those defined in the dictionary um if it turns out that neither of those is available then I use an index specifier instead index specifiers are weak they may not even be good for one launch of the application if you add or delete any objects at all your index specifiers are going to change and any that you might have stored in script variables just aren't going to be any good anymore or they're going to point to a different object and that could be bad in order to create an object specifier you're going to call an API that's going to need two pieces of information what container do I belong in and what does my container call me and that's what these two first two things are about every scriptable object i create has a pointer back to its parent do not retain your parent pointer this creates a loop and your objects will never go away you also need the an object also needs to know what its parent calls it what element relationship does it belong to I have a method called siblings it simply passes back the name of the method that that then this collection of objects back to the container these two pieces of information are going to be necessary to create your own object specifier so I keep them around all the time and all my object another thing I do as a favor to myself is every one of my scriptable objects has a nsdictionary in it called attributes and I use this to store the data for all the properties of the object now I can take this nsdictionary flatten it write it out to the disk read it back in later if i use a uuid to give it a unique ID I've now got a persistent object that i can use across several launches of the application several runs of the script several days from now I can go back and get that same data and use it in a scriptable way again this does not show up in my Apple script dictionary each individual property shows up in my Apple script dictionary but physically inside I keep them all in an NS dictionaries it's nice it's easy does a lot of stuff for you um now you need to create your actual model objects the things that you've decided to define in your dictionary you're going to want to create an object in and inherits from your scriptable base class so now you don't have to worry about names or IDs or object specifiers that's all done you are going to need to initialize this object and the way cocoa scripting works it creates an object first then it calls the various set methods to set the parameters you need to work with this you need to have an anit method that doesn't take any parameters it has to create an object that's ready to use right now to do that you might need to do some defensive programming make sure that check checking pointers for nil and things like that that object has to be safe to use right away because the way cocoa is going to use it is it's going to allocate it it's going to initialize it and then it's going to call the set methods to set what's in it it's not safe to do that you're going to have trouble Coco scripting is also well not just cocoa scripting put cocoa itself is going to expect you to have a deallocate method so that you can put away all your toys applescript is very is very memory intent at coco scripting is very member intensive you create and delete a lot of objects to process a particular apple event you want to make sure that you're not leaking so you want to make sure that you chained to any deallocation methods flow many any base classes you inherit from as well you want your scriptable objects to have properties and the way you do that in cocoa scripting is by creating a method with the property name for getting that value and another method that says set property name for setting the value the part that's here in italics is the part that you want to change to the property names that you've selected when you design your dictionary your dictionary also has element relationships and there's there's varying levels of support for that that you can that you can do in your cocoa scriptable objects the most basic one is to provide a method that has the same name as the element name and it bends back to whoever calls it an array of objects of that type this is this is the minimum amount necessary for a cocoa scripting application there are more things that you can do to make your application more more efficient but this is the start you have to start here the first time you come through this I just want you to create the methods they don't really have to do anything but the element relationships have to at least fake it a little bit so that you can test this stuff we're trying to get to the point where we can we can write some test scripts see if our program even works at all and then we're going to go back we're going to create this skeleton and then we're going to go back and put some muscles on it you also every everything is an element of some other object your top-level objects are going to be elements of the application itself in order to do that you're going to have to add element relationship methods to the NSF plication object we don't want you to have to subclass NS application if you don't want to if you do that for some other reason great but you don't have to do it for scripting you can use an objective c category or a delegate to add the methods that you need to the application object you may also have properties of the application there's no place to put these you can't change the list of ivars in the NFF l'occasion object you could if you subclass tick but we want to try to avoid that but since there's only one application object it's okay to go ahead and use Global's for these for any persistent properties that the application itself might have normally we want to avoid using Global's but this is an instance where it might be okay now you want to be able to create and delete objects you want to be able to insert them into collections and remove them from collections and Coco scripting again it takes the element names that you've decided to use in your dictionary create method names out of them and then you write those methods so you want to be able to insert elements into in through the element relationship and there's two ways to do that you can do it positionally or you can do an independent of position um sometimes doing it positionally is important if you're creating deleting windows you might want to create them in the front you might want to create them in the back might want to create them in between existing windows so you'd want to insert things to add index on other things that you create there's really no implicit order to them it's okay if they just go at the end in that case you can do a simpler insertion the team that doesn't take an index either one of these will work you may end up for various reasons you may end up wanting to do both these are both going to be used anytime you make a new object in your Apple script you also want to be able to remove things from the from the collection that's always done by index that's the way cocoa scripting works the object may be found in any one of a number of ways but when it finally gets deleted it's going to get deleted by index inside your code and this gets called by the deletes or there's there's enhanced element accessors that can make things more efficient for instance if you if you are implementing a database and you are using you you IDs for the to identify the records you could potentially have millions of these you don't simply want to have a method that creates an array and passes them all back that's not practical your programs not going to work very well there are enhanced methods that allow you to get objects directly by index by name and by unique ID these can be a whole lot more efficient than just searching a big huge array the decision of whether or not you want to do this it's a performance consideration you want to build your program the simple way first measure it and see if you need it but in the case of millions of records in a database it's pretty obvious you're going to need to do this all the details for this we're covered in last year's session if you've got the dvds it was section 303 if not there's a web page on the developer site that tells you a lot about this and on your cds there's cocoa scripting release notes which also describes how to do this now we want to test our objects we've got this skeleton it doesn't really do anything yet we got a bunch of objects they've got a bunch of phony properties they've got some phony elements we can't really do anything useful yet but we can start writing our test scripts first thing that I do is I put a logging macro in every single method that I write all the getters all the setters all the element accessors I put a logging macro in there and I have a switch here that I can turn on and off whenever I want to test my application see what it's doing try to figure out why it's not handling an apple event correctly I turn this switch on and run it and I get all sorts of stuff in the console log but it tells me blind by line where I've been in my program what I did what I did right and what I did wrong nice to know where you've been in your program it's nicer still to know why cocoa scripting will help you out there that this first line here if you type it into your terminal application it will turn on cocoa scripting own logging facility every time cocoa scripting gets an incoming apple event it uses your dictionary to parse it pull up figure out what all the pieces are as soon as Carlos Krypton's reach that point if this switch is on it logs what it thinks that message what it thinks that Apple event says now that you've got that information of what the incoming apple event looks like and then a log of everything that your program did to try to respond to that Apple event can help you a lot in debugging it if you have certain kinds of errors in your dictionary cocoa scripting may not be able to form a script command out of what it is it's received in that case you're going to have to go down one law one layer lower and get the apple event manager to tell you what that happen what that Apple event looks like you again you type these commands into your terminal application you need the first one and one or more of the others and then you have to launch your application from inside the terminal and then in the terminal scroll you will see a plement manager doing the same thing every time he gets an apple event he tears the part looks at it says what he thinks it means and puts it in and puts it in the terminal log this is all at a lower level all you're going to see at this level is for byte codes not very much in the way of interpretation but it can tell you it can tell you probably the reason why cocoa scripting is having a hard time with that event so then you want it you want to start writing some scripts and the first script you want to write is one that probes your entire object hierarchy touches every object touches every property gives you maximum coverage so you can see if your program is is written correctly and with a with apple script that's relatively easy thing to do applescript supports the every modifier which it's a it's a range specifier that says I want to act over the entire collection of objects and it also supports cocoa scripting supports for you for free the properties property which returns a record of all the properties of a given object so here in the course of just about nine lines of apple script I've managed to probe the entire object hierarchy of the folder action too sweet this script tells me that everything's there everything works time to go back and start writing some code so I'm going to go I'm going to want to go back to all the methods that I created before all the properties all the set properties all the element relationships and I want to populate them with real data now the element relationships are going to get their their data from various api's or collections of data inside your program that may already exist and the properties the properties are going to draw those their data from those actual objects once you've put some muscles into these routines you can go back and you can rerun all of your test scripts and you'll see a big change from the first time the first time you just gotta buy it back a bunch of bureaus and missing values this time you'll start to get back some real data objects with real names and real property is set to real values once you've reached this point you want to write even more test scripts you want to be able to make sure you don't have any regressions as you add more features as you add more capability you want to make sure you don't break anything that was already working before and you know one of the things you want to do is test accessing your objects by all the various means that they can be accessed simplest is index you can just count them and loop through them and get each one and get its properties to do a thorough test here for folder actions you'd have to have an inner loop that did the same thing to every script but I ran out of room on this slide you can also access things by name you want to make sure that that works this is going to this is going to test an important part of your program that Apple script does not require that that the object names be unique you may in the implementation in your program require that these names be unique but one way or the other you need to run this test if you've got two objects with the same name if you allow that you should find in this test but you can only ever really get to the first one if you support unique IDs you want to make sure that that kind of access works so you want to write nested loops here that access every object by its unique ID and this was one of the most important every scriptable object needs to offer up an object specifier for itself so that you can find that same object again later and do something new to it you got to make sure that those object specifiers really work that they really get you back to the same object that they were supposed to be and so you want to write a test for that loop through every object X get an object specifier for it then go back and get the properties using that object specifier and make sure that it's the object you thought it was and you want to make something new you want to create a new element and insert it into a collection of elements you do that with the make new verb that's part of the standard suite this is particularly interesting if you do this if you do this with all of the logging turned on you'll find out a lot about how your program works you'll find out a lot about how cocoa scripting works and you'll see that just to create a simple to create a single object and insert it into into a collection will end up calling every property access Iran that object and every element access or in the hierarchy all the way back to the application one of the most powerful features of Apple scripts are whose clauses that I'll allow you to select objects based on whether or not they satisfy a certain test so you want to make sure that you write some good tests of whose clauses the folder action supports an enabled flag for every object so here I've written some whose clauses based on the setting of the enabled flag to go into your folder actions set some of the enables legs on some of them to off and run this script you should get varying results and even though the last two events look very similar there is a subtle difference the presence of those parentheses will cause those last two events to actually return different collections of objects we talked about some other scenarios that you could find yourself in most common is adding script ability to an existing application it's a little bit less flexibility than you had when you were starting from scratch but you do a lot of the same things you one thing that I would suggest is that you use objective-c categories to add the scripting methods to an existing application you're not you don't have to go into the source files for the existing objects and actually change them you can put your scripting in a separate file created in the form of a category it's a very powerful way of modifying existing objects but it's also non intrusive if there's any point in the development cycle where you have a crisis of faith and you think that your scripting implementation is horribly screwed up your application and you don't know what to do about it you can go into Xcode and simply uncheck the scripting files rebuild your app and try it again and find out that maybe it was that guy next to you have messed it up not you mom or maybe it wasn't you and then you can fix it objective-c categories are a great way of building script ability alongside your existing objects without mucking them up too much you still do have the issue of an it method that doesn't take any parameters you might find that your existing objects aren't built that way that your existing objects having an it method that takes a whole bunch of parameters basically setting all of the properties at once at the same time that the object is created Coco scripting isn't going to work that way it's going to want in an interpreters and again you've got to make sure that the result at the end of that init method is a safe object whose methods can be called right now and it isn't going to be reference any nil pointers and again you're going to need a deallocate method because you're going to be creating and deleting a lot of these things in the course of handling apple event so you don't want gleek once you've created your categories alongside your existing objects you're going to have to implement all of your various properties together and setters and your element names and your element relationships you may find that some of the properties that you need already exist in the object so you just go ahead and reuse them on the X of the way that the dictionary has constructed the external name for a property and its internal name don't have to be closely related so you've got a getter in a setter for the name for instance you can just go ahead and reuse that if you find that the Apple stripped version of this getter and setter need to be slightly different than the other then you can wrap one around the other but one way or another you have to satisfy all of these properties by creating methods to access them same thing with the element relationship if you'll you'll need to create the element relationships in your scripting categories if you can't reuse any of the existing ones for instance NS application already has an ordered documents method and cocoa scripting reuses that for its own purposes there's no reason to create a new one and again you want to extend the NS applications so that your top-level objects are all elements of the application and again we would suggest to use active c category or a delegate to do that for the same reason is it's not intrusive you don't have to mess with the real NFL acacia knob ject and while you're doing this you should add your logging macro to every method that you create then we're going to go through the same steps we went through before we're going to write want to write a bunch of scripts to test this with even though some of the functionality might not be there yet and we want to go back and add some muscle to our objects still in those property accessors so that they get at real data still in those are those element accessors so they pass back collections of real objects then go back and rerun all of your scripts and make sure that the differences you see and the results are the ones that you expected the last situation is the toughest one and that's a adding script ability to to a large application that depends on a framework that is not itself scriptable and cannot easily be made scriptable um again though you want to go through most of the same steps you want to define a real good dictionary first then you want to write then you want to define the scriptable objects properties and element relationships that that bring that real bring that dictionary to life and you want to do this as if you were starting from scratch you've got this existing framework that you can't penetrate too easily and you want to add cocoa scripting to it just create the cocoa scripting objects as if you were starting from scratch as if this other application didn't even exist do the same thing we did before give them just enough functionality so that you can write some interesting test then you're going to want to go back and add muscle to these objects by taking all the property accessors and element accessors and tying them back into existing api's and existing objects inside the impenetrable framework this is where the complexity can arise the object model that you chose to express in your Apple script dictionary and the object model that exists in this impenetrable framework might not match up you might have to do some sorting and searching and recombining of things to get them to work right this is where this scenario can become difficult but when you're done or you think you're done you can go back and rerun all of your scripts that you wrote and see if you've got the results that you were expecting till it should give you an indication that you've done it correctly we promised that we would talk about cocoa and carbon and we haven't said anything about carving yet so what about carbon um well you can still script a carbon application in the same way that you always have the the the OSL is still there it still works and you can use it and it's so that's very well documented in the inner application communication document and there's also Mac Tech is now the guardian of all the old develop articles this one is a particularly good one a cookbook a recipe for taking carbon application and making it scriptable they weren't even called carbon applications back when this was written um so you can do it that way it's not easy but we've all done it at least once and it can be done um you I would suggest that you seriously consider migrating to Coco it's not I know it's not trivial carbon is is a first-class citizen and it's it's going to be supported forever um but Coco is the way we encourage you to develop new apps if you reach a point in your development cycle where you're really considering to chucking it all and starting over again consider starting over again in cocoa I wouldn't start over again just for scripting but it's certainly a factor if you do rewrite your application in Cocoa objective-c and cocoa scripting will make the scripting part of your job very easy a year ago we promised that we would come up with a API for carbon scripting that was just as easy to use as cocoa just as powerful to all the same things for you leveraged all of that existing power and we thought and thought and thought of how to do this and it was really hard and we were going to end up having to rewrite almost everything that cocoa scripting did and it occurred to us well maybe we could just use cocoa scripting um so we conducted an experiment and found out that yes as a matter of fact it pretty much just works you can use cocoa scripting in an otherwise carbon application this is really a special case of the third scenario you've got this big impenetrable framework that's hard to make scriptable you want to build a cocoa scripting implementation alongside of it and tie it into the existing implementation you can actually do that with any existing carbon application it's not hard but it's not trivial there's a few tricks that you need to know few modifications you need to make to your application startup code but once you've done that cocoa scripting just works um there is a price though you don't get this for free um it can have a performance impact on your application and the only way for you to find out what that is is to just measure it yourself and the two things that you're going to need to measure a launch time and memory usage so you want to get a baseline for those before you start your work you don't have to do your entire scripting and implementation to find out what this what this impact is going to be what you do have to make the changes to your startup code once you change your startup code you can relaunch your application and you'll get a pretty good idea of what pulling in cocoa scripting is going to do to your application it'll slow down the launch it will increase the footprint now you haven't written your code yet but you haven't written any carbon script ability code yet either and the presumption is that they will be about equivalent that the hit that you're taking is the overhead for cocoa scripting and you can measure that without having to write all the code first if you really want to do this contact developer technical support and put scripting hybrid in the subject of the of your email and you will get a response from John mantri on about how to go about doing this um like I said it's not hard but you got to know a few things um there's lots and lots of documentation to help you make your application scriptable if you're the the most important part of it is the design in your dictionary and these are these places here good places to go to find out information about that you also need to implement objective-c or other objects to bring your dictionary to life there's more detailed information about how to do that at these places cocoa and carbon are both are both documented here and the apple script language guide is going to be valuable to anybody that writing scriptable applications or writing Apple scripts any anybody along the line and users testers engineers marketers everybody should be looking at the apple script language guide it teaches you how Apple script itself works and teaches you a lot about how your object about how your object model needs to inter interface with that each time we release new software we keep you up to date on the latest changes those are in these release notes which should be on your CDs and the interpretation communication technote is kind of an umbrella where you'll find almost all the rest of the stuff that we mentioned plus a whole bunch of other stuff about apple event an applescript if you're afraid you don't want to ask any new big questions you can go to the applescript QA and see if maybe the answer is already there um but don't be afraid to ask newbie questions they're really easy for us the answer and we feel like we've done a good deed and you can get sample code also and you can get information from outside the applescript website has a wealth of information including dozens and dozens of sample scripts for apple applications and other applications creating synergy between them you should definitely visit that site and there's books and websites published by third parties they also have very valuable information and the applescript website is a good place to start to find most of those there's a section in there that's just all about third-party websites that you can go to to learn even more if these are all the sessions that you missed on but if you get the dvds you can watch them there or maybe some of you guys were at them this is today's session and the rest of the ones that we're going to have I mentioned tomorrow we're going to talk about using Apple script to test your applications and also we're going to there's going to be a session where self-knowing is going to talk about apple script for system administrators alva scripts a tremendous tool for system administrators save them a lot of time if you want your system administrator to love you you should write a good scriptable app and if you need to get to get to us directly Todd Fernandez is my boss South Egwene is our marketing manager Jason's our technology manager and John Mondrian is our DTS contact should always go through John Mondrian first he's going to have the quickest answer for you if it's already been asked and he's going to direct it to the right person if it hasn't already been asked you