Какие хорошие сценарии Xcode для ускорения разработки? - PullRequest
9 голосов
/ 23 июня 2009

Xcode позволяет создавать автоматизированные сценарии для выполнения повторяющихся задач. Какие сценарии вы написали для ускорения разработки?

Ответы [ 6 ]

4 голосов
/ 31 января 2010

Это улучшение скрипта «Создать свойство и синтез для переменных экземпляра», который Лоуренс Джонстон разместил выше.

Настройки:

Ввод: весь документ Каталог: Домашний каталог Выход: Отменить вывод Ошибки: игнорировать ошибки (или оповещения, если вы хотите их видеть)

Выберите любое количество переменных, и он создаст свойства и syns для всех них. Он даже создаст / отредактирует ваш метод dalloc по мере необходимости.

Редактировать результаты, если они не совсем правильные (копировать или сохранить и т. Д.)

Обрабатывает больше вещей, таких как имя хранилища в нижней части, поведение, освобождение,…

Ссылка на источник и обсуждение: 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;
4 голосов
/ 04 июля 2009

Я создал три для моего JSON.Framework для Какао и iPhone . Они заботятся о следующем:

  • Создает образ диска выпуска с динамической встроенной платформой, пользовательским SDK для iPhone, документацией API и некоторыми файлами документации.
  • Запустите Doxygen через источник, чтобы создать Xcode-совместимый набор документации и установить его. Это означает, что когда вы ищете вещи в поиске документации Xcode, ваша документация также может быть найдена.
  • Запустите Doxygen через источник, чтобы обновить зарегистрированную версию документации API в самом дереве исходного кода. Это очень удобно, если вы используете Subversion (что предполагает), поскольку документация всегда актуальна для вашей ветки. Отлично, если вы размещаете на Google Code, например.

Остерегайтесь некоторых жестко заданных значений, специфичных для проекта, ниже. Я не хотел нарушать сценарии, редактируя их. Они запускаются из фазы пользовательских сценариев в XCode. Вы можете увидеть, как они интегрированы в проект Xcode для проекта, указанного выше.

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:

#!/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/Documentation
APIDOCDIR=$SOURCE_ROOT/documentation

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        = NO

EOF

#  Run doxygen on the updated config file.
$DOXYGEN $DOXYFILE

# Replace the old dir with the newly generated one.
rm -f $APIDOCDIR/*
cp -p $DOCSET/html/* $APIDOCDIR
cd $APIDOCDIR

# Revert files that differ only in the timestamp.
svn diff *.html | diffstat | awk '$3 == 2 { print $1 }' | xargs svn revert

# Add/remove files from subversion.
svn st | awk '
    $1 == "?" { print "svn add", $2 }
    $1 == "!" { print "svn delete",  $2 }
' | sh -

svn propset svn:mime-type text/html *.html
svn propset svn:mime-type text/css *.css
svn propset svn:mime-type image/png *.png
svn propset svn:mime-type image/gif *.gif
2 голосов
/ 23 июня 2009

Вот один из способов создать метод описания для класса. Выделите раздел объявления переменных экземпляра (@interface ... {...}) и выполните сценарий. Затем вставьте результат в вашу реализацию. Я использую это вместе с po objectName в GDB. Если FIXME появляется в выводе, это означает, что это нераспознанный тип. Вы можете либо добавить его в сценарий, либо вручную выбрать нужный форматный спецификатор.

#!/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"\n@"  -""" % 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"\n@"  -')

outputStrings.append("\"")

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

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

print "".join(outputStrings),
2 голосов
/ 23 июня 2009

Вот один из способов регистрации метода и его аргументов каждый раз, когда он выполняется (выберите определение метода через ложь с открывающей фигурной скобкой и выполните сценарий).Если FIXME появляется в выводе, это означает, что это нераспознанный тип.Вы можете либо добавить его в сценарий, либо вручную выбрать нужный форматный спецификатор.

#!/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),
1 голос
/ 23 июня 2009

Вот еще один, который я нашел где-то еще, который создает директивы свойств @property (copy) и @synthesize для переменной экземпляра. Можно было бы внести некоторые улучшения (скажем, чтобы вы могли синтезировать несколько переменных одновременно), но это лучше, чем создавать их вручную.

Выберите переменную экземпляра, для которой вы хотите создать свойство, и активируйте скрипт.

Если я хочу (сохранить) вместо (копировать), я просто активирую сценарий и изменяю его на сохранение вручную (это достаточно умно, чтобы не включать (копировать) примитивные типы, такие как int для начала).

#! /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 голосов
/ 14 июня 2010

Это создает для вас методы @proptery, @synthesize, dealloc, viewDidUnload и public. Простая интеграция с XCode:

http://github.com/holtwick/xobjc

...