2009-06-23 4 views

Antwort

4

Ich habe drei für meine JSON.Framework for Cocoa and the iPhone erstellt. Diese kümmern sich um die folgenden:.

  • Erzeugt Release Disk Image mit dynamischem Embedded Framework benutzerdefinierte iPhone SDK, API-Dokumentation und einige Dokumentationsdateien in
  • Run Doxygen über die Quelle eine Xcode-kompatible Dokumentation zu erstellen Stellen Sie dies ein und installieren Sie es. Das heißt, wenn Sie in der Dokumentationssuche nach Xcode suchen, finden Sie auch Ihre Dokumentation.
  • Führen Sie Doxygen über die Quelle aus, um eine eingecheckte Version der API-Dokumentation im Quellbaum selbst zu aktualisieren. Das ist sehr praktisch, wenn Sie Subversion verwenden (was sie annimmt), da die Dokumentation immer aktuell für den Zweig ist, in dem Sie sich befinden. Großartig, wenn Sie zum Beispiel auf Google Code hosten.

Beachten Sie einige hartcodierte projektspezifische Werte im Folgenden. Ich wollte die Skripte nicht potentiell unterbrechen, indem ich diese herausarbeite. Diese werden von einer benutzerdefinierten Skriptphase in Xcode gestartet. Sie können sehen, wie sie in das Xcode-Projekt für das oben verlinkte Projekt integriert sind.

CreateDiskImage.sh:

#!/bin/sh 

set -x 

# Determine the project name and version 
VERS=$(agvtool mvers -terse1) 

# Derived names 
VOLNAME=${PROJECT}_${VERS} 
DISK_IMAGE=$BUILD_DIR/$VOLNAME 
DISK_IMAGE_FILE=$INSTALL_DIR/$VOLNAME.dmg 

# Remove old targets 
rm -f $DISK_IMAGE_FILE 
test -d $DISK_IMAGE && chmod -R +w $DISK_IMAGE && rm -rf $DISK_IMAGE 
mkdir -p $DISK_IMAGE 

# Create the Embedded framework and copy it to the disk image. 
xcodebuild -target JSON -configuration Release install || exit 1 
cp -p -R $INSTALL_DIR/../Frameworks/$PROJECT.framework $DISK_IMAGE 

IPHONE_SDK=2.2.1 

# Create the iPhone SDK directly in the disk image folder. 
xcodebuild -target libjson -configuration Release -sdk iphoneos$IPHONE_SDK install \ 
    ARCHS=armv6 \ 
    DSTROOT=$DISK_IMAGE/SDKs/JSON/iphoneos.sdk || exit 1 
sed -e "s/%PROJECT%/$PROJECT/g" \ 
    -e "s/%VERS%/$VERS/g" \ 
    -e "s/%IPHONE_SDK%/$IPHONE_SDK/g" \ 
    $SOURCE_ROOT/Resources/iphoneos.sdk/SDKSettings.plist > $DISK_IMAGE/SDKs/JSON/iphoneos.sdk/SDKSettings.plist || exit 1 

xcodebuild -target libjson -configuration Release -sdk iphonesimulator$IPHONE_SDK install \ 
    ARCHS=i386 \ 
    DSTROOT=$DISK_IMAGE/SDKs/JSON/iphonesimulator.sdk || exit 1 
sed -e "s/%PROJECT%/$PROJECT/g" \ 
    -e "s/%VERS%/$VERS/g" \ 
    -e "s/%IPHONE_SDK%/$IPHONE_SDK/g" \ 
    $SOURCE_ROOT/Resources/iphonesimulator.sdk/SDKSettings.plist > $DISK_IMAGE/SDKs/JSON/iphonesimulator.sdk/SDKSettings.plist || exit 1  

# Allow linking statically into normal OS X apps 
xcodebuild -target libjson -configuration Release -sdk macosx10.5 install \ 
    DSTROOT=$DISK_IMAGE/SDKs/JSON/macosx.sdk || exit 1 

# Copy the source verbatim into the disk image. 
cp -p -R $SOURCE_ROOT/Source $DISK_IMAGE/$PROJECT 
rm -rf $DISK_IMAGE/$PROJECT/.svn 

# Create the documentation 
xcodebuild -target Documentation -configuration Release install || exit 1 
cp -p -R $INSTALL_DIR/Documentation/html $DISK_IMAGE/Documentation 
rm -rf $DISK_IMAGE/Documentation/.svn 

cat <<HTML > $DISK_IMAGE/Documentation.html 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> 
<script type="text/javascript"> 
<!-- 
window.location = "Documentation/index.html" 
//--> 
</script> 
</head> 
<body> 
<p>Aw, shucks! I tried to redirect you to the <a href="Documentaton/index.html">api documentation</a> but obviously failed. Please find it yourself. </p> 
</body> 
</html> 
HTML 

cp -p $SOURCE_ROOT/README $DISK_IMAGE 
cp -p $SOURCE_ROOT/Credits.rtf $DISK_IMAGE 
cp -p $SOURCE_ROOT/Install.rtf $DISK_IMAGE 
cp -p $SOURCE_ROOT/Changes.rtf $DISK_IMAGE 

hdiutil create -fs HFS+ -volname $VOLNAME -srcfolder $DISK_IMAGE $DISK_IMAGE_FILE 

InstallDocumentation.sh:

#!/bin/sh 
# See also http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 

set -x 

VERSION=$(agvtool mvers -terse1) 

DOXYFILE=$DERIVED_FILES_DIR/doxygen.config 
DOXYGEN=/Applications/Doxygen.app/Contents/Resources/doxygen 
DOCSET=$INSTALL_DIR/Docset 

rm -rf $DOCSET 
mkdir -p $DOCSET || exit 1 
mkdir -p $DERIVED_FILES_DIR || exit 1 

if ! test -x $DOXYGEN ; then 
    echo "*** Install Doxygen to get documentation generated for you automatically ***" 
    exit 1 
fi 

# Create a doxygen configuration file with only the settings we care about 
$DOXYGEN -g - > $DOXYFILE 

cat <<EOF >> $DOXYFILE 

PROJECT_NAME   = $FULL_PRODUCT_NAME 
PROJECT_NUMBER   = $VERSION 
OUTPUT_DIRECTORY  = $DOCSET 
INPUT     = $SOURCE_ROOT/Source 
FILE_PATTERNS   = *.h *.m 

HIDE_UNDOC_MEMBERS  = YES 
HIDE_UNDOC_CLASSES  = YES 
HIDE_UNDOC_RELATIONS = YES 
REPEAT_BRIEF   = NO 
CASE_SENSE_NAMES  = YES 
INLINE_INHERITED_MEMB = YES 
SHOW_FILES    = NO 
SHOW_INCLUDE_FILES  = NO 
GENERATE_LATEX   = NO 
GENERATE_HTML   = YES 
GENERATE_DOCSET  = YES 
DOCSET_FEEDNAME  = "$PROJECT.framework API Documentation" 
DOCSET_BUNDLE_ID  = org.brautaset.$PROJECT 

EOF 

# Run doxygen on the updated config file. 
# doxygen creates a Makefile that does most of the heavy lifting. 
$DOXYGEN $DOXYFILE 

# make will invoke docsetutil. Take a look at the Makefile to see how this is done. 
make -C $DOCSET/html install 

# Construct a temporary applescript file to tell Xcode to load a docset. 
rm -f $TEMP_DIR/loadDocSet.scpt 

cat <<EOF > $TEMP_DIR/loadDocSet.scpt 
tell application "Xcode" 
    load documentation set with path "/Users/$USER/Library/Developer/Shared/Documentation/DocSets/org.brautaset.${PROJECT}.docset/" 
end tell 
EOF 

# Run the load-docset applescript command. 
osascript $TEMP_DIR/loadDocSet.scpt 

RegenerateDocumentation.sh:

2

Hier können Sie eine Methode und ihre Argumente bei jeder Ausführung protokollieren (Wählen Sie die Methodendefinition durch die Lüge mit der öffnenden Klammer aus und führen Sie das Skript aus). Wenn FIXME in der Ausgabe angezeigt wird, bedeutet dies, dass es sich um einen nicht erkannten Typ handelt. Sie können es entweder zum Skript hinzufügen oder den richtigen Formatbezeichner manuell auswählen.

#!/usr/bin/python 

# LogMethod 
# Selection 
# Selection 
# Insert after Selection 
# Display in Alert 

import sys 
import re 

input = sys.stdin.read() 

methodPieces = re.findall("""(\w*:)""", input) 
vars = re.findall(""":\(([^)]*)\)[ ]?(\w*)""", input) 

outputStrings = ["\n NSLog(@\""] 

# Method taking no parameters 
if not methodPieces: 
    outputStrings.append(re.findall("""(\w*)[ ]?{""", input)[0]) 

for (methodPiece, var) in zip(methodPieces, vars): 
    type = var[0] 
    outputStrings.append(methodPiece) 
    if "**" in type: 
     outputStrings.append("%p") 
    elif "*" in type: 
     if "char" in type: 
      outputStrings.append("%c") 
     else: 
      outputStrings.append("%@") 
    else: 
     if "int" in type or "NSInteger" in type or "BOOL" in type: 
      outputStrings.append("%i") 
     elif "NSUInteger" in type: 
      outputStrings.append("%u") 
     elif "id" in type: 
      outputStrings.append("%@") 
     elif "NSTimeInterval" in type: 
      outputStrings.append("%f") 
     elif "SEL" in type: 
      outputString.append("%s") 
     else: 
      outputStrings.append('"FIXME"') 
    if not methodPiece == methodPieces[-1]: 
     outputStrings.append('\\n"\n   @"') 

outputStrings.append("\"") 

for var in vars: 
    name = var[1] 
    outputStrings.append(",\n   ") 
    outputStrings.append(name) 

outputStrings.append(");") 

print "".join(outputStrings), 
2

Hier ist eine eine Beschreibung Methode für eine Klasse zu erstellen. Markieren Sie den Deklarationsabschnitt der Instanzvariablen (@interface ... {...}) und führen Sie das Skript aus. Fügen Sie das Ergebnis dann in Ihre Implementierung ein. Ich benutze dieses zusammen mit po objectName in GDB. Wenn FIXME in der Ausgabe angezeigt wird, bedeutet dies, dass es sich um einen nicht erkannten Typ handelt. Sie können es entweder zum Skript hinzufügen oder den richtigen Formatbezeichner manuell auswählen.

#!/usr/bin/python 

# Create description method for class 
# Selection 
# Selection 
# Insert after Selection 
# Display in Alert 

import sys 
import re 

input = sys.stdin.read() 

className = re.findall("""(?:@interface)(\w*)""", input)[0] 
vars = re.findall("""(\w*[ ][*]?)(\w*?)_?;""", input) 

outputStrings = ["- (NSString *)description {\n"] 
outputStrings.append("""return [NSString stringWithFormat:@"%s :\\n"\[email protected]" -""" % className) 

for type, var in vars: 
    outputStrings.append("%s:" % var) 
    if "**" in type: 
     outputStrings.append("%p") 
    elif "*" in type: 
     if "char" in type: 
      outputStrings.append("%c") 
     else: 
      outputStrings.append("%@") 
    else: 
     if "int" in type or "NSInteger" in type or "BOOL" in type: 
      outputStrings.append("%i") 
     elif "NSUInteger" in type: 
      outputStrings.append("%u") 
     elif "id" in type: 
      outputStrings.append("%@") 
     elif "NSTimeInterval" in type: 
      outputStrings.append("%f") 
     elif "SEL" in type: 
      outputString.append("%s") 
     else: 
      outputStrings.append('"FIXME"') 

    if not var == vars[-1][1]: 
     outputStrings.append(',\\n"\[email protected]" -') 

outputStrings.append("\"") 

for type, var in vars: 
    outputStrings.append(",\n") 
    outputStrings.append("[self %s]" % var) 

outputStrings.append("];\n}") 

print "".join(outputStrings), 
1

Hier ist eine, die ich woanders gefunden, die @property (Kopie) und @synthesize Eigenschaft Richtlinien für eine Instanz Variable erzeugt. Es könnte ein bisschen verbessert werden (zB um mehrere Variablen auf einmal zu synthetisieren), aber es ist besser, als sie von Hand zu erstellen.

Wählen Sie die Instanzvariable aus, für die Sie eine Eigenschaft erstellen möchten, und aktivieren Sie das Skript.

Wenn ich ein (behalten) möchte anstelle (kopieren) ich nur aktivieren Sie das Skript und ändern Sie es manuell beibehalten (es ist schlau genug, die (kopieren) auf primitiven Typen wie int zu beginnen mit).

#! /usr/bin/perl -w 

#Create property from instance variable 

#Entire Document 
#Home Directory 
#Discard Output 
#Display in Alert 

use strict; 

# Get the header file contents from Xcode user scripts 
my $headerFileContents = <<'HEADERFILECONTENTS'; 
%%%{PBXAllText}%%% 
HEADERFILECONTENTS 

# Get the indices of the selection from Xcode user scripts 
my $selectionStartIndex = %%%{PBXSelectionStart}%%%; 
my $selectionEndIndex = %%%{PBXSelectionEnd}%%%; 

# Get path of the header file 
my $implementationFilePath = "%%%{PBXFilePath}%%%"; 
my $headerFilePath = $implementationFilePath; 

# Look for an implemenation file with a ".m" or ".mm" extension 
$implementationFilePath =~ s/\.[hm]*$/.m/; 
if (!(-e $implementationFilePath)) 
{ 
    $implementationFilePath =~ s/.m$/.mm/; 
} 

# Handle subroutine to trime whitespace off both ends of a string 
sub trim 
{ 
    my $string = shift; 
    $string =~ s/^\s*(.*?)\s*$/$1/; 
    return $string; 
} 

# Get the selection out of the header file 
my $selectedText = substr $headerFileContents, $selectionStartIndex, ($selectionEndIndex - $selectionStartIndex); 
$selectedText = trim $selectedText; 

my $type = ""; 
my $asterisk = ""; 
my $name = ""; 
my $behavior = ""; 

# Test that the selection is: 
# At series of identifiers (the type name and access specifiers) 
# Possibly an asterisk 
# Another identifier (the variable name) 
# A semi-colon 
if (length($selectedText) && ($selectedText =~ /([_A-Za-z][_A-Za-z0-9]*\s*)+([\s\*]+)([_A-Za-z][_A-Za-z0-9]*);/)) 
{ 
    $type = $1; 
    $type = trim $type; 
    $asterisk = $2; 
    $asterisk = trim $asterisk; 
    $name = $3; 
    $behavior = ""; 
    if (defined($asterisk) && length($asterisk) == 1) 
    { 
     $behavior = "(copy) "; #"(nonatomic, retain) "; 
    } 
    else 
    { 
     $asterisk = ""; 
    } 
} 
else 
{ 
    exit 1; 
} 

# Find the closing brace (end of the class variables section) 
my $remainderOfHeader = substr $headerFileContents, $selectionEndIndex; 
my $indexAfterClosingBrace = $selectionEndIndex + index($remainderOfHeader, "\n}\n") + 3; 
if ($indexAfterClosingBrace == -1) 
{ 
    exit 1; 
} 

# Determine if we need to add a newline in front of the property declaration 
my $leadingNewline = "\n"; 
if (substr($headerFileContents, $indexAfterClosingBrace, 1) eq "\n") 
{ 
    $indexAfterClosingBrace += 1; 
    $leadingNewline = ""; 
} 

# Determine if we need to add a newline after the property declaration 
my $trailingNewline = "\n"; 
if (substr($headerFileContents, $indexAfterClosingBrace, 9) eq "\@property") 
{ 
    $trailingNewline = ""; 
} 

# Create and insert the propert declaration 
my $propertyDeclaration = $leadingNewline . "\@property " . $behavior . $type . " " . $asterisk . $name . ";\n" . $trailingNewline; 
substr($headerFileContents, $indexAfterClosingBrace, 0) = $propertyDeclaration; 

my $replaceFileContentsScript = <<'REPLACEFILESCRIPT'; 
on run argv 
    set fileAlias to POSIX file (item 1 of argv) 
    set newDocText to (item 2 of argv) 
    tell application "Xcode" 
     set doc to open fileAlias 
     set text of doc to newDocText 
    end tell 
end run 
REPLACEFILESCRIPT 

# Use Applescript to replace the contents of the header file 
# (I could have used the "Output" of the Xcode user script instead) 
system 'osascript', '-e', $replaceFileContentsScript, $headerFilePath, $headerFileContents; 

# Stop now if the implementation file can't be found 
if (!(-e $implementationFilePath)) 
{ 
    exit 1; 
} 

my $getFileContentsScript = <<'GETFILESCRIPT'; 
on run argv 
    set fileAlias to POSIX file (item 1 of argv) 
    tell application "Xcode" 
     set doc to open fileAlias 
     set docText to text of doc 
    end tell 
    return docText 
end run 
GETFILESCRIPT 

# Get the contents of the implmentation file 
open(SCRIPTFILE, '-|') || exec 'osascript', '-e', $getFileContentsScript, $implementationFilePath; 
my $implementationFileContents = do {local $/; <SCRIPTFILE>}; 
close(SCRIPTFILE); 

# Look for the class implementation statement 
if (length($implementationFileContents) && ($implementationFileContents =~ /(\@implementation [_A-Za-z][_A-Za-z0-9]*\n)/)) 
{ 
    my $matchString = $1; 
    my $indexAfterMatch = index($implementationFileContents, $matchString) + length($matchString); 

    # Determine if we want a newline before the synthesize statement 
    $leadingNewline = "\n"; 
    if (substr($implementationFileContents, $indexAfterMatch, 1) eq "\n") 
    { 
     $indexAfterMatch += 1; 
     $leadingNewline = ""; 
    } 

    # Determine if we want a newline after the synthesize statement 
    $trailingNewline = "\n"; 
    if (substr($implementationFileContents, $indexAfterMatch, 11) eq "\@synthesize") 
    { 
     $trailingNewline = ""; 
    } 

    # Create and insert the synthesize statement 
    my $synthesizeStatement = $leadingNewline . "\@synthesize " . $name . ";\n" . $trailingNewline; 
    substr($implementationFileContents, $indexAfterMatch, 0) = $synthesizeStatement; 

    # Use Applescript to replace the contents of the implementation file in Xcode 
    system 'osascript', '-e', $replaceFileContentsScript, $implementationFilePath, $implementationFileContents; 
} 

exit 0; 
+0

In XCode 3.2.2 dieses Skript alle crashy verschiedene XCode Ausnahmen und macht XCode gibt. Ich bin mir nicht sicher, wie ein Skript das mit XCode machen könnte, also stelle ich mir vor, dass es eine XCode-Sache ist. –

+0

Hinweis: Crasiness ist nur dann wahr, wenn Ihre Einstellungen im Skript nicht korrekt sind. –

4

Dies ist eine Verbesserung des Skripts "Create Property und Synths für Instanzvariablen", das Lawrence Johnston oben veröffentlicht hat.

Einstellungen:

Input: Gesamtes Dokument Verzeichnis: Home-Verzeichnis Ausgang: Verwerfen Ausgabe Fehler: Fehler ignorieren (oder Benachrichtigung, wenn Sie sie sehen wollen)

eine beliebige Anzahl von Variablen auswählen und Erstelle Eigenschaften und Syns für alle von ihnen. Es wird sogar Ihre Dalloc-Methode nach Bedarf erstellen/bearbeiten.

bearbeiten bis die Ergebnisse, wenn sie nicht genau richtig (Kopie vs. behalten, etc.)

mehr Dinge Griffe wie underbar Speichername, Verhalten, dealloc, ...

Link zu, wo dies kommt von und Diskussion: http://cocoawithlove.com/2008/12/instance-variable-to-synthesized.html

#! /usr/bin/perl -w 

# Created by Matt Gallagher on 20/10/08. 
# Copyright 2008 Matt Gallagher. All rights reserved. 
# 
# Enhancements by Yung-Luen Lan and Mike Schrag on 12/08/09. 
# (mainly: multiple lines) 
# Copyright 2009 Yung-Luen Lan and Mike Schrag. All rights reserved. 
# 
# Enhancements by Pierre Bernard on 20/09/09. 
# (mainly: underbar storage name, behavior, dealloc,…) 
# Copyright 2009 Pierre Bernard. All rights reserved. 
# 
# Permission is given to use this source code file without charge in any 
# project, commercial or otherwise, entirely at your risk, with the condition 
# that any redistribution (in part or whole) of source code must retain 
# this copyright and permission notice. Attribution in compiled projects is 
# appreciated but not required. 

use strict; 

# Get the header file contents from Xcode user scripts 
my $headerFileContents = <<'HEADERFILECONTENTS'; 
%%%{PBXAllText}%%% 
HEADERFILECONTENTS 

# Get the indices of the selection from Xcode user scripts 
my $selectionStartIndex = %%%{PBXSelectionStart}%%%; 
my $selectionEndIndex = %%%{PBXSelectionEnd}%%%; 



# Find the closing brace (end of the class variables section) 
my $remainderOfHeader = substr $headerFileContents, $selectionEndIndex; 
my $indexAfterClosingBrace = $selectionEndIndex + index($remainderOfHeader, "\n}\n") + 3; 
if ($indexAfterClosingBrace == -1) 
{ 
exit 1; 
} 


# Get path of the header file 
my $implementationFilePath = "%%%{PBXFilePath}%%%"; 
my $headerFilePath = $implementationFilePath; 

# Look for an implemenation file with a ".m" or ".mm" extension 
$implementationFilePath =~ s/\.[hm]*$/.m/; 
if (!(-e $implementationFilePath)) 
{ 
$implementationFilePath =~ s/.m$/.mm/; 
} 

# Stop now if the implementation file can't be found 
if (!(-e $implementationFilePath)) 
{ 
exit 1; 
} 


my $propertyDeclarations = ''; 
my $synthesizeStatements = ''; 
my $releaseStatements = ''; 



# Handle subroutine to trim whitespace off both ends of a string 
sub trim 
{ 
my $string = shift; 
$string =~ s/^\s*(.*?)\s*$/$1/; 
return $string; 
} 

# Get the selection out of the header file 
my $selectedText = substr $headerFileContents, $selectionStartIndex, ($selectionEndIndex - $selectionStartIndex); 
$selectedText = trim $selectedText; 

my $selectedLine; 

foreach $selectedLine (split(/\n+/, $selectedText)) { 
my $type = ''; 
my $asterisk = ''; 
my $name = ''; 
my $behavior = ''; 

# Test that the selection is: 
# At series of identifiers (the type name and access specifiers) 
# Possibly an asterisk 
# Another identifier (the variable name) 
# A semi-colon 
if (length($selectedLine) && ($selectedLine =~ /([_A-Za-z][_A-Za-z0-9]*\s*)+([\s\*]+)([_A-Za-z][_A-Za-z0-9]*);/)) 
{ 
    $type = $1; 
    $type = trim $type; 
    $asterisk = $2; 
    $asterisk = trim $asterisk; 
    $name = $3; 
    $behavior = 'assign'; 

    if (defined($asterisk) && length($asterisk) == 1) 
    { 
    if (($type eq 'NSString') || ($type eq 'NSArray') || ($type eq 'NSDictionary') || ($type eq 'NSSet')) 
    { 
    $behavior = 'copy'; 
    } 
    else 
    { 
    if (($name =~ /Delegate/) || ($name =~ /delegate/) || ($type =~ /Delegate/) || ($type =~ /delegate/)) 
    { 
    $behavior = 'assign'; 
    } 
    else 
    { 
    $behavior = 'retain'; 
    } 
    } 
    } 
    else 
    { 
    if ($type eq 'id') 
    { 
    $behavior = 'copy'; 
    } 

    $asterisk = ''; 
    } 
} 
else 
{ 
    next; 
} 

my $storageName = ''; 

if ($name =~ /_([_A-Za-z][_A-Za-z0-9]*)/) { 
    $storageName = $name; 
    $name = $1; 
} 


# Create and insert the propert declaration 
my $propertyDeclaration = "\@property (nonatomic, $behavior) $type " . $asterisk . $name . ";\n"; 

$propertyDeclarations = $propertyDeclarations . $propertyDeclaration; 



# Create and insert the synthesize statement 
my $synthesizeStatement = ''; 

if (length($storageName)) 
{ 
    $synthesizeStatement = "\@synthesize $name = $storageName;\n"; 
} 
else 
{ 
    $synthesizeStatement = "\@synthesize $name;\n"; 
} 

$synthesizeStatements = $synthesizeStatements . $synthesizeStatement; 



# Create and insert release statement 
my $releaseName = $name; 
my $releaseStatement = ''; 

if (length($storageName)) 
{ 
    $releaseName = $storageName; 
} 

if ($behavior eq 'assign') 
{ 
    if ($type eq 'SEL') 
    { 
    $releaseStatement = "\t$releaseName = NULL;\n"; 
    } 
} 
else 
{ 
    $releaseStatement = "\t[$releaseName release];\n\t$releaseName = nil;\n"; 
} 

$releaseStatements = $releaseStatements . $releaseStatement; 
} 

my $leadingNewline = ''; 
my $trailingNewline = ''; 

# Determine if we need to add a newline in front of the property declarations 
if (substr($headerFileContents, $indexAfterClosingBrace, 1) eq "\n") 
{ 
$indexAfterClosingBrace += 1; 
$leadingNewline = ''; 
} 
else 
{ 
$leadingNewline = "\n"; 
} 

# Determine if we need to add a newline after the property declarations 
if (substr($headerFileContents, $indexAfterClosingBrace, 9) eq '@property') 
{ 
$trailingNewline = ''; 
} 
else 
{ 
$trailingNewline = "\n"; 
} 

substr($headerFileContents, $indexAfterClosingBrace, 0) = $leadingNewline . $propertyDeclarations . $trailingNewline; 

my $replaceFileContentsScript = <<'REPLACEFILESCRIPT'; 
on run argv 
set fileAlias to POSIX file (item 1 of argv) 
set newDocText to (item 2 of argv) 
tell application "Xcode" 
    set doc to open fileAlias 
    set text of doc to (text 1 thru -2 of newDocText) 
end tell 
end run 
REPLACEFILESCRIPT 

# Use Applescript to replace the contents of the header file 
# (I could have used the "Output" of the Xcode user script instead) 
system 'osascript', '-e', $replaceFileContentsScript, $headerFilePath, $headerFileContents; 



my $getFileContentsScript = <<'GETFILESCRIPT'; 
on run argv 
set fileAlias to POSIX file (item 1 of argv) 
tell application "Xcode" 
    set doc to open fileAlias 
    set docText to text of doc 
end tell 
return docText 
end run 
GETFILESCRIPT 

# Get the contents of the implmentation file 
open(SCRIPTFILE, '-|') || exec 'osascript', '-e', $getFileContentsScript, $implementationFilePath; 
my $implementationFileContents = do {local $/; <SCRIPTFILE>}; 
close(SCRIPTFILE); 

# Look for the class implementation statement 
if (length($implementationFileContents) && ($implementationFileContents =~ /(\@implementation [_A-Za-z][_A-Za-z0-9]*\n)/)) 
{ 
my $matchString = $1; 
my $indexAfterMatch = index($implementationFileContents, $matchString) + length($matchString); 

# Determine if we want a newline before the synthesize statement 
if (substr($implementationFileContents, $indexAfterMatch, 1) eq "\n") 
{ 
    $indexAfterMatch += 1; 
    $leadingNewline = ''; 
} 
else 
{ 
    $leadingNewline = "\n"; 
} 

# Determine if we want a newline after the synthesize statement 
if (substr($implementationFileContents, $indexAfterMatch, 11) eq '@synthesize') 
{ 
    $trailingNewline = ''; 
} 
else 
{ 
    $trailingNewline = "\n"; 
} 

substr($implementationFileContents, $indexAfterMatch, 0) = $leadingNewline. $synthesizeStatements . $trailingNewline; 

if ($implementationFileContents =~ /([ \t]*\[.*super.*dealloc.*\].*;.*\n)/) 
{ 
    my $deallocMatch = $1; 
    my $indexAfterDeallocMatch = index($implementationFileContents, $deallocMatch); 

    substr($implementationFileContents, $indexAfterDeallocMatch, 0) = "$releaseStatements\n"; 

} 
elsif ($implementationFileContents =~ /(\@synthesize .*\n)*(\@synthesize [^\n]*\n)/s) { 
    my $synthesizeMatch = $2; 
    my $indexAfterSynthesizeMatch = index($implementationFileContents, $synthesizeMatch) + length($synthesizeMatch); 
    my $deallocMethod = "\n- (void)dealloc\n{\n$releaseStatements\n\t[super dealloc];\n}\n"; 

    substr($implementationFileContents, $indexAfterSynthesizeMatch, 0) = $deallocMethod; 
} 

# Use Applescript to replace the contents of the implementation file in Xcode 
system 'osascript', '-e', $replaceFileContentsScript, $implementationFilePath, $implementationFileContents; 
} 

exit 0;