<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>toxicsoftware.com &#187; Source</title>
	<atom:link href="http://toxicsoftware.com/tag/source/feed/" rel="self" type="application/rss+xml" />
	<link>http://toxicsoftware.com</link>
	<description>RANDOMIZE USR 0</description>
	<lastBuildDate>Sun, 01 Aug 2010 17:49:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Run Python Script</title>
		<link>http://toxicsoftware.com/run-python-script/</link>
		<comments>http://toxicsoftware.com/run-python-script/#comments</comments>
		<pubDate>Fri, 14 Dec 2007 16:14:16 +0000</pubDate>
		<dc:creator>schwa</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[Automator]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[public]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Source]]></category>

		<guid isPermaLink="false">http://toxicsoftware.com/run-python-script/</guid>
		<description><![CDATA[Important see updates at end of post I&#8217;ve written an Automator action that allows you to write python scripts directly inside your Automator workflow. &#8220;Run Python Script&#8221; Automator action (catchy title) is written using Python and PyObjC (now built-in to &#8230; <a href="http://toxicsoftware.com/run-python-script/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><em>Important</em> see updates at end of post</p>

<p>I&#8217;ve written an Automator action that allows you to write python scripts directly inside your Automator workflow.</p>

<p><a href="http://www.flickr.com/photos/61285556@N00/2110974754" title="View 'RunPythonScriptIcon' on Flickr.com"><img src="http://farm3.static.flickr.com/2237/2110974754_6e5540298b_o.png" alt="RunPythonScriptIcon" /></a></p>

<p>&#8220;<a href="http://bitbucket.org/schwa/toxic-public/src/tip/Projects/Automator/RunPythonScriptAction/Output/Run%20Python%20Script.action.tar.bz2">Run Python Script</a>&#8221; Automator action (catchy title) is written using Python and <a href="http://pyobjc.sourceforge.net/">PyObjC</a> (now built-in to Mac OS X 10.5). Apple already provides &#8220;Run AppleScript&#8221; and &#8220;Run Shell Script&#8221; actions with Automator which give Automator a high degree of flexibility. However Python is my preferred scripting language and by writing a custom action purely for Python I was able to take advantage of some PyObjC features that in my opinion make my action superior to the provided Apple scripting action. I&#8217;m releasing all the <a href="http://bitbucket.org/schwa/toxic-public/src/tip/Projects/Automator/RunPythonScriptAction/">source code</a> to the action under the <a href="http://www.opensource.org/licenses/bsd-license.php">BSD Open Source</a> license.</p>

<p>One of the main advantages of the action is that Python (with the help of PyObjC) understands the AppleEvent descriptors that Automator uses to pass data between workflow actions. This allows the user to create a custom action that accepts and provides data of any type. In contrast Apple&#8217;s &#8220;Run Shell Script&#8221; action can only accept and provide text (usually limited to file paths). Some work does need to be done to make working with any data (which is represented by NSAppleEventDescriptor objects) more convenient.</p>

<p>The default Python script for a new action in a workflow follows:</p>

<pre><code>import sys

def main(input, *args, **kwargs):
    '''Your script goes here.'''
    print 'Hello world'
    return sys.stdout
</code></pre>

<p><a href="http://www.flickr.com/photos/61285556@N00/2110978140" title="View 'RunPythonScriptMain' on Flickr.com"><img src="http://farm3.static.flickr.com/2286/2110978140_4c336656f7_m.jpg" alt="RunPythonScriptMain" /></a></p>

<p>This is pretty simple. The action will optionally convert the input into Python types (currently limited to converting typeAlias AppleEvent descriptors into path strings) to allow simple processing. Output is (optionally) converted from Python types to native Automator types. See the Examples directory for more.</p>

<p>The following screenshot shows the action used in a real workflow. This workflow asks the user for a keyword and then the Python action downloads photos from the <a href="http://morguefile.com/">morguefile</a> public stock photo archive that are related to the keyword. Once download it performs some processing on the files (scales them to 640 by 480) and produces a PDF &#8220;Contact Book&#8221; from the images.</p>

<p><a href="http://www.flickr.com/photos/61285556@N00/2110196661" title="View 'RunPythonScriptScreenshot' on Flickr.com"><img src="http://farm3.static.flickr.com/2169/2110196661_e9f178f475_m.jpg" alt="RunPythonScriptScreenshot" /></a></p>

<p>The <a href="http://bitbucket.org/schwa/toxic-public/src/tip/Projects/Automator/RunPythonScriptAction/">source code</a> uses a 10.5 specific technique to create Python based bundles. It also has a simple Python syntax colouring NSTextView (using Python itself to colourise the source).</p>

<p>I&#8217;m calling the Action a 0.1 release and have some plans/ideas for further releases. See the <a href="http://bitbucket.org/schwa/toxic-public/src/tip/Projects/Automator/RunPythonScriptAction/TODO.txt">TODO list</a>.</p>

<p><em>Update</em>: I&#8217;ve added a <a href="http://toxicsoftware.com/s3_uploader/">sample script</a> showing how to upload files to Amazon S3 from within a workflow.</p>

<p>The code in subversion is a lot newer than the binary I&#8217;m linking to. If possible do a  checkout and build the plugin yourself.</p>

<p><em>Update</em>: This Automator action has issues on Snow Leopard and some Leopard versions. Use at your own risk.</p>

<p><em>Update</em>: Automator&#8217;s &#8220;Run Terminal Script&#8221; looks like it supports and understands Python native. That means, although my .action was better (syntax highlighting, better control of input and output, better logging, etc), I probably won&#8217;t bother to update it to Snow Leopard.</p>

<p><img src="http://toxicsoftware.com/wordpress/wp-content/uploads/Screen-shot-2009-10-16-at-11.02.36-AM.png" alt="Screen shot 2009-10-16 at 11.02.36 AM.png" border="0" width="25%" height="25%" /></p>
]]></content:encoded>
			<wfw:commentRss>http://toxicsoftware.com/run-python-script/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Grab that Invocation</title>
		<link>http://toxicsoftware.com/grab-that-invocation/</link>
		<comments>http://toxicsoftware.com/grab-that-invocation/#comments</comments>
		<pubDate>Sat, 24 Jun 2006 00:25:43 +0000</pubDate>
		<dc:creator>schwa</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[NSInvocation]]></category>
		<category><![CDATA[Source]]></category>

		<guid isPermaLink="false">http://toxicsoftware.com/grab-that-invocation/</guid>
		<description><![CDATA[CInvocationGrabber is a Cocoa class to help with creating NSInvocation objects. NSInvocation objects are Cocoa&#8217;s equivalent of &#8220;functors&#8221; and are extremely handy. But unfortunately creating them is often a pain. For example, take the following code showing how to create &#8230; <a href="http://toxicsoftware.com/grab-that-invocation/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Projects/Misc/InvocationGrabber/">CInvocationGrabber</a> is a Cocoa class to help with creating <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/index.html#//apple_ref/doc/uid/TP40003671">NSInvocation</a> objects.</p>

<p>NSInvocation objects are Cocoa&#8217;s equivalent of &#8220;<a href="http://en.wikipedia.org/wiki/Function_object">functors</a>&#8221; and are extremely handy. But unfortunately creating them is often a pain. For example, take the following code showing how to create a simple NSInvocation:</p>

<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#400080;">NSInvocation</span> *theInvocation = [<span style="color:#400080;">NSInvocation</span> <span style="color:#6c0540;">invocationWithMethodSignature:</span>[theString <span style="color:#6c0540;">methodSignatureForSelector:</span><span style="color:#881350;">@selector</span>(insertString:atIndex:)]];<br />
[theInvocation <span style="color:#6c0540;">setSelector:</span><span style="color:#881350;">@selector</span>(insertString:atIndex:)];<br />
[theInvocation <span style="color:#6c0540;">setTarget:</span>theString];<br />
<span style="color:#400080;">NSString</span> *theFirstArgument = <span style="color:#760f15;">&quot;Hello World&quot;</span>;<br />
[theInvocation <span style="color:#6c0540;">setArgument:</span>&amp;theFirstArgument <span style="color:#6c0540;">atIndex:</span><span style="color:#0000ff;">2</span>];<br />
<span style="color:#881350;">unsigned</span> theSecondArgument = <span style="color:#0000ff;">42</span>;<br />
[theInvocation <span style="color:#6c0540;">setArgument:</span>&amp;theFirstArgument <span style="color:#6c0540;">atIndex:</span><span style="color:#0000ff;">3</span>];</div>

<p>The code to create the same NSInvocation using my CInvocationGrabber class looks like this:</p>

<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; ">CInvocationGrabber *theGrabber = [CInvocationGrabber <span style="color:#6c0540;">invocationGrabber</span>];<br />
[[theGrabber <span style="color:#6c0540;">prepareWithInvocationTarget:</span>theString] <span style="color:#6c0540;">insertString:</span><span style="color:#760f15;">@&quot;Hello World&quot;</span> <span style="color:#6c0540;">atIndex:</span><span style="color:#0000ff;">42</span>];<br />
<span style="color:#400080;">NSInvocation</span> *theInvocation = [theGrabber <span style="color:#6c0540;">invocation</span>]</div>

<p>Obviously the primary benefit is that there is a lot less code. A secondary benefit is that you don&#8217;t have to store your parameters on the heap and can just pass them into the &#8216;grabbed&#8217; method.</p>

<p>Now that I&#8217;ve been using CInvocationGrabber for a few months I find I am using NSInvocations more and more. I&#8217;m using them in places where I would normally have written a little delegate method. For example just today I needed to write code that called a method after a time delay. Normally I would have wrapped it up in a NSTimer delegate method, but with CInvocationHelper I just used the invocation variant of NSTimer. Although I wasn&#8217;t saving many lines of code in this example, I was reducing the clutter in the class.</p>

<p>Cocoa developers with a keen eye might spot the similarity between CInvocationGrabber and Cocoa&#8217;s NSUndoManager APIs. This code is directly inspired by NSUndoManager&#8217;s prepareWithInvocation method.</p>
]]></content:encoded>
			<wfw:commentRss>http://toxicsoftware.com/grab-that-invocation/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>mdfind2 updated</title>
		<link>http://toxicsoftware.com/mdfind2-updated/</link>
		<comments>http://toxicsoftware.com/mdfind2-updated/#comments</comments>
		<pubDate>Sat, 03 Jun 2006 15:22:11 +0000</pubDate>
		<dc:creator>schwa</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[mdfind]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Source]]></category>
		<category><![CDATA[Spotlight]]></category>

		<guid isPermaLink="false">http://toxicsoftware.com/mdfind2-updated/</guid>
		<description><![CDATA[I&#8217;ve just updated mdfind2. The most important change is that it is now a universal binary. I&#8217;ve also improved the command-line parsing (it now uses getopt_long) and prints usage information on error. Links: Subversion Repository: http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Spotlight/mdfind2/ Binary: http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Spotlight/mdfind2/Output/mdfind2.tar.bz2]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just updated <a href="/blog/mdfind2">mdfind2</a>. The most important change is that it is now a universal binary. I&#8217;ve also improved the command-line parsing (it now uses getopt_long) and prints usage information on error.</p>

<p>Links:</p>

<p>Subversion Repository: <a href="http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Spotlight/mdfind2/">http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Spotlight/mdfind2/</a></p>

<p>Binary: <a href="http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Spotlight/mdfind2/Output/mdfind2.tar.bz2">http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Spotlight/mdfind2/Output/mdfind2.tar.bz2</a></p>
]]></content:encoded>
			<wfw:commentRss>http://toxicsoftware.com/mdfind2-updated/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
