Сценарий XCode для генерации/синтезирования свойств

Жесткие ссылки очень полезны при выполнении возрастающих резервных копий. См. rsnapshot, например. Идея состоит в том, чтобы сделать копию с помощью жестких ссылок:

  • резервное копирование копии номер n к n + 1
  • копия копируют n - 1 к n
  • ...
  • копия копирует 0 для резервного копирования 1
  • , обновление копирует 0 с любыми измененными файлами.

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

9
задан Lawrence Johnston 20 July 2009 в 01:27
поделиться

6 ответов

Я использую аксессуар, который делает это и многое другое.

http://www.kevincallahan.org/software/accessorizer.html

очень недорогой и мощный.

7
ответ дан 4 December 2019 в 14:30
поделиться

Это то, что я придумал на основе того, которое я нашел давным-давно, переписанного на Python и с улучшениями, которые, помимо прочего, могут генерировать несколько свойств одновременно.

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

По-прежнему есть некоторые крайние случаи с несколькими @interfaces или @implementations в файле, а также некоторые с необычными идентификаторами или размещением звездочки (как в * const), но они должны охватывать большинство типичных стилей кодирования. Не стесняйтесь редактировать / публиковать изменения, если вы исправите любой из этих случаев.

#!/usr/bin/python

# Takes a header file with one or more instance variables selected
# and creates properties and synthesize directives for the selected properties.

# Accepts google-style instance variables with a tailing underscore and
# creates an appropriately named property without underscore.

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

import os
import re
import subprocess

# AppleScripts for altering contents of files via Xcode
setFileContentsScript = """\
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 \
"""

getFileContentsScript = """\
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 \
"""

# Get variables from Xcode
headerFileText = """%%%{PBXAllText}%%%"""
selectionStartIndex = %%%{PBXSelectionStart}%%%
selectionEndIndex = %%%{PBXSelectionEnd}%%%
selectedText = headerFileText[selectionStartIndex:selectionEndIndex]

headerFilePath = """%%%{PBXFilePath}%%%"""

# Look for an implementation file with .m or .mm extension
implementationFilePath = headerFilePath[:-1] + "m"
if not os.path.exists(implementationFilePath):
    implementationFilePath += "m"

instanceVariablesRegex = re.compile(
  """^\s*((?:(?:\w+)\s+)*(?:(?:\w+)))""" + # Identifier(s)
  """([*]?)\\s*""" + # An optional asterisk
  """(\\w+?)(_?);""", # The variable name
  re.M)

# Now for each instance variable in the selected section
properties = ""
synthesizes = ""

for lineMatch in instanceVariablesRegex.findall(selectedText):
    types = " ".join(lineMatch[0].split()) # Clean up consequtive whitespace
    asterisk = lineMatch[1]
    variableName = lineMatch[2]
    trailingUnderscore = lineMatch[3]

    pointerPropertyAttributes = "(copy) " # Attributes if variable is pointer
    if not asterisk:
      pointerPropertyAttributes = ""

    newProperty = "@property %s%s %s%s;\n" % (pointerPropertyAttributes,
                                             types,
                                             asterisk,
                                             variableName)

    # If there's a trailing underscore, we need to let the synthesize
    # know which backing variable it's using
    newSynthesize = "@synthesize %s%s;\n" % (variableName,
                                           trailingUnderscore and
                                           " = %s_" % variableName)

    properties += newProperty
    synthesizes += newSynthesize

# Check to make sure at least 1 properties was found to generate
if not properties:
  os.sys.stderr.writelines("No properties found to generate")
  exit(-1)

# We want to insert the new properties either immediately after the last
# existing property or at the end of the instance variable section
findLastPropertyRegex = re.compile("^@interface.*?{.*?}.*?\\n" +
                                   "(?:.*^\\s*@property.*?\\n)?", re.M | re.S)
headerInsertIndex = findLastPropertyRegex.search(headerFileText).end()

# Add new lines on either side if this is the only property in the file
addedNewLine = "\n"
if re.search("^\s*@property", headerFileText, re.M):
  # Not the only property, don't add
  addedNewLine = ""

newHeaderFileText = "%s%s%s%s" % (headerFileText[:headerInsertIndex],
                                addedNewLine,
                                properties,
                                headerFileText[headerInsertIndex:])

subprocess.call(["osascript",
                "-e",
                setFileContentsScript,
                headerFilePath,
                newHeaderFileText])


if not os.path.exists(implementationFilePath):
  os.sys.stdout.writelines("No implementation file found")
  exit(0)

implementationFileText = subprocess.Popen(
  ["osascript",
   "-e",
  getFileContentsScript,
   implementationFilePath],
  stdout=subprocess.PIPE).communicate()[0]

# We want to insert the synthesizes either immediately after the last existing
# @synthesize or after the @implementation directive
lastSynthesizeRegex = re.compile("^\\s*@implementation.*?\\n" +
                                "(?:.*^\\s*@synthesize.*?\\n)?", re.M | re.S)

implementationInsertIndex = \
  lastSynthesizeRegex.search(implementationFileText).end()

# Add new lines on either side if this is the only synthesize in the file
addedNewLine = "\n"
if re.search("^\s*@synthesize", implementationFileText, re.M):
  # Not the only synthesize, don't add
  addedNewLine = ""

newImplementationFileText = "%s%s%s%s" % \
                  (implementationFileText[:implementationInsertIndex],
                   addedNewLine,
                   synthesizes,
                   implementationFileText[implementationInsertIndex:])

subprocess.call(["osascript",
                 "-e",
                 setFileContentsScript,
                 implementationFilePath,
                 newImplementationFileText])

# Switch Xcode back to header file
subprocess.Popen(["osascript",
                  "-e",
                  getFileContentsScript,
                  headerFilePath],
                 stdout=subprocess.PIPE).communicate()
2
ответ дан 4 December 2019 в 14:30
поделиться

Вот один, который я написал вчера, чтобы выполнить директивы @property, прежде чем через несколько часов столкнулся с этим вопросом. Это простой текстовый фильтр, и его было бы тривиально расширить до директив @synthesize (добавьте соответствующее предложение when в оператор case и внесите соответствующие дополнения в when block_end ), и немного больше работы по расширению его для обработки нескольких экземпляров реализации @ interface / @ в одном файле (отслеживая их имена - это можно сделать с помощью захвата регулярных выражений, как и все остальное в сценарии) :

#! /usr/bin/ruby

# -------------- Basic Definitions -----------------------------

doc = "%%%{PBXFilePath}%%%"

# regular expressions

search_exp = /[[:space:]]*([[a-zA-Z0-9]]*)[[:space:]]\*([a-zA-Z0-9]*)/
interface_start = /@interface/
block_end = /^\}/

#initializing variables

properties_list = []
properties_string = ""
reading_interface = 0

#---------------- Start Processing -----------------------------

file = File.open(doc, "r").readlines

file.each do |line| 

# capture the regular expression matches only in the 
# interface declaration and print out the matching
# property declarations

  case line

  # start capturing
  when interface_start
    reading_interface = 1
    puts line

  # capture and keep in properties_list
  when search_exp
    if (reading_interface == 1) then
      data = Regexp.last_match
      properties_list <<  data
    end
    puts line

  # unpack properties_list and print out the property
  # declarations
  when block_end
    if (reading_interface == 1) then
      reading_interface = 0
      properties_list.each do |pair|
        properties_string << "@property (readwrite, copy) #{pair[0].lstrip};\n"
      end
      puts line
      puts "\n" + properties_string
    end
  else puts line
  end

end

Я запускаю это, используя «без ввода» и «заменить содержимое документа» в качестве параметров ввода-вывода в редакторе пользовательских сценариев.

0
ответ дан 4 December 2019 в 14:30
поделиться

Вот пользовательский скрипт, который я сейчас использую - он работает с одной переменной экземпляра за раз. Он пытается использовать правильный механизм сохранения (простые типы не сохраняются), а также создает оператор @synthesize в файле реализации - в настоящее время он еще не создает для вас операторы dealloc.

#! /usr/bin/perl -w

#Input: Selection
#Directory: Selection
#Output: Display in Alert
#Errors: 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);

#my $otherText = substr $headerFileContents, $selectionStartIndex;
#my $pulledText = "";
#if ( length($otherText) && $otherText =~ /.*$(^.*;).*/ )
#{
#    $pulledText = $1;
#}
#
#
#print $pulledText;


$selectedText = trim $selectedText;


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

# 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 = "(nonatomic, retain) ";
    }
    else
    {
        $behavior = "(nonatomic) ";
        $asterisk = "";
    }
}
else
{
    print "Bailing, error in Regex";
    exit 1;
}

# special case, see if we need to keep around an IBOUTLET declaration.
if ( length($selectedText) && ($selectedText =~ /IBOutlet/) )
{
   $iboutlet = "IBOutlet ";
}

# 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 proper declaration
my $propertyDeclaration = $leadingNewline . "\@property " . $behavior . $iboutlet . $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;
1
ответ дан 4 December 2019 в 14:30
поделиться

Инициализатор коллекции внутри инициализатора объекта:

MailMessage mail = new MailMessage {
   To = { new MailAddress("a@example.com"), new MailAddress("b@example.com") },
   Subject = "Password Recovery"
};

Можно инициализировать целое дерево в одном выражении.

-121--1749489-

Я не согласен с тем, что, поскольку у вас есть основной класс игры, вся логика должна происходить в этом классе.

Чрезмерное упрощение здесь имитирует ваш пример только для того, чтобы сделать мою точку зрения:

mainloop:
  moveEntities()
  resolveCollisions()   [objects may "disappear"/explode here]
  drawEntities()        [drawing before or after cleanEntitites() ain't an issue, a dead entity won't draw itself]
  cleanDeadEntities()

Теперь у вас есть класс Bubble:

Bubble implements Drawable {

handle( Needle needle ) {
    if ( needle collide with us ) {
        exploded = true;
    }
}

draw (...) {
   if (!exploded) {
      draw();
     }
  }
}

Так что, конечно, есть основная петля, которая заботится о передаче сообщений вокруг между сущностями, но логика, связанная со столкновением пузыря и иглы, определенно не в основном классе игры.

Я почти уверен, что даже в вашем случае вся логика, связанная с движением, происходит не в основном классе.

Поэтому я не согласен с вашим утверждением, что вы написали жирным шрифтом, что «вся логика происходит в основном классе».

Это просто неправильно.

Что касается хорошего дизайна: если вы можете легко предоставить другой «вид» вашей игры (например, мини-карту) и если вы можете легко кодировать «идеальный повторитель кадра за кадр», то ваш дизайн, вероятно, не так уж и плох (то есть: записывая только входные данные и время, в которое они произошли, вы должны иметь возможность воссоздать игру точно так, как она была сыграна. Вот как Age of Empires, Warcraft 3 и т.д. делают свое воспроизведение: записываются только пользовательские вводы и время, в которое они произошли [вот почему файлы воспроизведения обычно такие крошечные]).

-121--2556112-

Accessorizer http://www.kevincallahan.org/software/accessorizer.html делает это и многое другое. Он также обрабатывает пользовательские префиксы и постфиксы (суффиксы). Если вам нужен знак подчеркивания Google, вы получите его. Если вы хотите изменить его, измените его на лету - нет необходимости редактировать сценарии. Кроме того, существует таблица значений по умолчанию, в которой можно определить спецификаторы свойств по умолчанию на основе типа передаваемого ivar (копировать, сохранять, только для чтения, назначать и т.д.). Он выполняет обнаружение IBOutlet и автоматически вставляет ключевое слово IBOutlet, обнуляет ваши представления для -viewDidUnload, выполняет несколько стилей dealloc. Он также пишет все эти волосатые аксессуары для коллекций (NSMuterArray и NSSet). Она выполняет архивирование ключей, различные подходы блокировки, она может сортировать ваше свойство и синтезировать блоки, писать код KVO, код Singleton, конвертировать в селектор, генерировать тэги HeeyDoc, NSLog () и многое другое... Она также имеет гибкую вкладку стилей для размещения фигурных скобок на новой линии или нет, для интервалов, для пользовательских имен аргументов и т.д. Большинство вещей обрабатывается через Службы, поэтому вы просто выбираете свой ivar блок, нажмите клавишу или два и вы закончили. Если свернуть Accessorizer с док-станции, его интерфейс не окажется на переднем плане, позволяя оставаться сфокусированным в Xcode или любом другом редакторе, поддерживающем Службы. Конечно, Accessorizer также записывает явные accessors (как в Objective-C 1.0) и позволяет переопределить свойства - все с простым переключением переключателя. Можно даже настроить переопределение на основе переданного типа. Посмотрите видео, чтобы увидеть его в действии.

0
ответ дан 4 December 2019 в 14:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: