Skip to content
Browse files

Merge branch 'development'

  • Loading branch information...
2 parents dbc050d + ef591e9 commit 50616ef1ad431342f3c1fc2a78249b63164a7e64 @tomaz committed Jan 17, 2011
Showing with 2,507 additions and 1,087 deletions.
  1. +1 −1 AppledocTests-Info.plist
  2. +1 −0 AppledocTests_prefix.pch
  3. +169 −82 Application/GBAppledocApplication.m
  4. +100 −31 Application/GBApplicationSettingsProvider.h
  5. +76 −34 Application/GBApplicationSettingsProvider.m
  6. +2 −1 Application/GBApplicationStringsProvider.m
  7. +13 −12 Application/GBCommentComponentsProvider.h
  8. +19 −31 Application/GBCommentComponentsProvider.m
  9. +1 −0 Common/GBTask.m
  10. +58 −0 Common/NSArray+GBArray.h
  11. +42 −0 Common/NSArray+GBArray.m
  12. +15 −0 Common/NSString+GBString.h
  13. +24 −0 Common/NSString+GBString.m
  14. +83 −32 Generating/GBDocSetOutputGenerator.m
  15. +2 −12 Generating/GBHTMLOutputGenerator.m
  16. +2 −2 Generating/GBHTMLTemplateVariablesProvider.m
  17. +31 −0 Generating/GBOutputGenerator.h
  18. +66 −2 Generating/GBOutputGenerator.m
  19. +13 −0 Model/GBAdoptedProtocolsProvider.m
  20. +4 −0 Model/GBCategoryData.m
  21. +5 −1 Model/GBClassData.m
  22. +32 −4 Model/GBComment.h
  23. +19 −9 Model/GBComment.m
  24. +1 −1 Model/GBCommentParagraph.m
  25. +1 −1 Model/GBMethodArgument.h
  26. +13 −0 Model/GBMethodData.m
  27. +7 −1 Model/GBMethodsProvider.h
  28. +23 −0 Model/GBMethodsProvider.m
  29. +1 −2 Model/GBParagraphListItem.m
  30. +4 −0 Model/GBProtocolData.m
  31. +1 −5 Model/GBSourceInfo.m
  32. +16 −1 Parsing/GBObjectiveCParser.m
  33. +15 −2 Parsing/GBTokenizer.h
  34. +5 −2 Parsing/GBTokenizer.m
  35. +624 −596 Processing/GBCommentsProcessor.m
  36. +13 −1 Processing/GBProcessor.m
  37. +43 −14 Readme.markdown
  38. +98 −0 Release Notes.markdown
  39. 0 Templates/docset/Contents/Resources/{ → Documents}/documents-template
  40. +5 −2 Templates/html/hierarchy-template.html
  41. +5 −2 Templates/html/index-template.html
  42. +12 −10 Templates/html/object-template.html
  43. +73 −78 Testing/GBApplicationSettingsProviderTesting.m
  44. +119 −15 Testing/GBApplicationTesting.m
  45. +31 −6 Testing/GBCommentTesting.m
  46. +2 −2 Testing/GBCommentsProcessor-BugsTesting.m
  47. +32 −27 Testing/GBCommentsProcessor-ComplexTesting.m
  48. +29 −29 Testing/GBCommentsProcessor-DecoratorItemsTesting.m
  49. +3 −3 Testing/GBCommentsProcessor-ExamplesTesting.m
  50. +234 −7 Testing/GBCommentsProcessor-LinkItemsTesting.m
  51. +7 −7 Testing/GBCommentsProcessor-MethodArgumentsTesting.m
  52. +3 −3 Testing/GBCommentsProcessor-OrderedListsTesting.m
  53. +4 −4 Testing/GBCommentsProcessor-TextItemsTesting.m
  54. +3 −3 Testing/GBCommentsProcessor-UnorderedListsTesting.m
  55. +2 −2 Testing/GBCommentsProcessor-WarningsTesting.m
  56. +14 −0 Testing/GBMethodDataTesting.m
  57. +22 −0 Testing/GBMethodsProviderTesting.m
  58. +32 −0 Testing/GBObjectiveCParser-CategoryParsingTesting.m
  59. +32 −0 Testing/GBObjectiveCParser-ClassParsingTesting.m
  60. +36 −0 Testing/GBObjectiveCParser-MethodsParsingTesting.m
  61. +32 −1 Testing/GBObjectiveCParser-ProtocolParsingTesting.m
  62. +73 −0 Testing/GBProcessor-CommentsTesting.m
  63. +29 −1 Testing/GBTemplateVariablesProvider-CommonTesting.m
  64. +15 −3 Testing/GBTokenizerTesting.m
  65. +2 −0 appledoc.m
  66. +12 −2 appledoc.xcodeproj/project.pbxproj
  67. +1 −0 appledoc_Prefix.pch
View
2 AppledocTests-Info.plist
@@ -17,6 +17,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
- <string>1</string>
+ <string>514</string>
</dict>
</plist>
View
1 AppledocTests_prefix.pch
@@ -10,6 +10,7 @@
#import <Cocoa/Cocoa.h>
#import "NSObject+GBObject.h"
#import "NSString+GBString.h"
+ #import "NSArray+GBArray.h"
#import "NSException+GBException.h"
#import "NSError+GBError.h"
#import "NSFileManager+GBFileManager.h"
View
251 Application/GBAppledocApplication.m
@@ -30,6 +30,10 @@
static NSString *kGBArgCreateHTML = @"create-html";
static NSString *kGBArgCreateDocSet = @"create-docset";
static NSString *kGBArgInstallDocSet = @"install-docset";
+static NSString *kGBArgPublishDocSet = @"publish-docset";
+static NSString *kGBArgKeepIntermediateFiles = @"keep-intermediate-files";
+
+static NSString *kGBArgRepeatFirstParagraph = @"repeat-first-par";
static NSString *kGBArgKeepUndocumentedObjects = @"keep-undocumented-objects";
static NSString *kGBArgKeepUndocumentedMembers = @"keep-undocumented-members";
static NSString *kGBArgFindUndocumentedMembersDocumentation = @"search-undocumented-doc";
@@ -41,13 +45,16 @@
static NSString *kGBArgWarnOnMissingCompanyIdentifier = @"warn-missing-company-id";
static NSString *kGBArgWarnOnUndocumentedObject = @"warn-undocumented-object";
static NSString *kGBArgWarnOnUndocumentedMember = @"warn-undocumented-member";
+static NSString *kGBArgWarnOnInvalidCrossReference = @"warn-invalid-crossref";
+static NSString *kGBArgWarnOnMissingMethodArgument = @"warn-missing-arg";
static NSString *kGBArgDocSetBundleIdentifier = @"docset-bundle-id";
static NSString *kGBArgDocSetBundleName = @"docset-bundle-name";
static NSString *kGBArgDocSetDescription = @"docset-desc";
static NSString *kGBArgDocSetCopyrightMessage = @"docset-copyright";
static NSString *kGBArgDocSetFeedName = @"docset-feed-name";
static NSString *kGBArgDocSetFeedURL = @"docset-feed-url";
+static NSString *kGBArgDocSetPackageURL = @"docset-package-url";
static NSString *kGBArgDocSetFallbackURL = @"docset-fallback-url";
static NSString *kGBArgDocSetPublisherIdentifier = @"docset-publisher-id";
static NSString *kGBArgDocSetPublisherName = @"docset-publisher-name";
@@ -56,6 +63,10 @@
static NSString *kGBArgDocSetCertificateIssuer = @"docset-cert-issuer";
static NSString *kGBArgDocSetCertificateSigner = @"docset-cert-signer";
+static NSString *kGBArgDocSetBundleFilename = @"docset-bundle-filename";
+static NSString *kGBArgDocSetAtomFilename = @"docset-atom-filename";
+static NSString *kGBArgDocSetPackageFilename = @"docset-package-filename";
+
static NSString *kGBArgLogFormat = @"logformat";
static NSString *kGBArgVerbose = @"verbose";
static NSString *kGBArgPrintSettings = @"print-settings";
@@ -71,9 +82,9 @@ @interface GBAppledocApplication ()
- (void)initializeLoggingSystem;
- (void)initializeGlobalSettingsAndValidateTemplates;
- (void)validateSettingsAndArguments:(NSArray *)arguments;
-- (void)printSettingsAndArguments:(NSArray *)arguments;
- (void)overrideSettingsWithGlobalSettingsFromPath:(NSString *)path;
- (BOOL)validateTemplatesPath:(NSString *)path error:(NSError **)error;
+- (NSString *)standardizeCurrentDirectoryForPath:(NSString *)path;
@property (readwrite, retain) GBApplicationSettingsProvider *settings;
@property (assign) NSString *logformat;
@property (assign) NSString *verbose;
@@ -88,6 +99,7 @@ - (BOOL)validateTemplatesPath:(NSString *)path error:(NSError **)error;
@interface GBAppledocApplication (UsagePrintout)
+- (void)printSettingsAndArguments:(NSArray *)arguments;
- (void)printVersion;
- (void)printHelp;
- (void)printHelpForShortOption:(NSString *)aShort longOption:(NSString *)aLong argument:(NSString *)argument description:(NSString *)description;
@@ -192,28 +204,39 @@ - (void)application:(DDCliApplication *)app willParseOptions:(DDGetoptLongParser
{ kGBArgDocSetFallbackURL, 0, DDGetoptRequiredArgument },
{ kGBArgDocSetFeedName, 0, DDGetoptRequiredArgument },
{ kGBArgDocSetFeedURL, 0, DDGetoptRequiredArgument },
+ { kGBArgDocSetPackageURL, 0, DDGetoptRequiredArgument },
{ kGBArgDocSetMinimumXcodeVersion, 0, DDGetoptRequiredArgument },
{ kGBArgDocSetPlatformFamily, 0, DDGetoptRequiredArgument },
{ kGBArgDocSetPublisherIdentifier, 0, DDGetoptRequiredArgument },
{ kGBArgDocSetPublisherName, 0, DDGetoptRequiredArgument },
{ kGBArgDocSetCopyrightMessage, 0, DDGetoptRequiredArgument },
+ { kGBArgDocSetBundleFilename, 0, DDGetoptRequiredArgument },
+ { kGBArgDocSetAtomFilename, 0, DDGetoptRequiredArgument },
+ { kGBArgDocSetPackageFilename, 0, DDGetoptRequiredArgument },
+
{ kGBArgCreateHTML, 'h', DDGetoptNoArgument },
{ kGBArgCreateDocSet, 'd', DDGetoptNoArgument },
{ kGBArgInstallDocSet, 'n', DDGetoptNoArgument },
+ { kGBArgPublishDocSet, 'u', DDGetoptNoArgument },
{ GBNoArg(kGBArgCreateHTML), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgCreateDocSet), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgInstallDocSet), 0, DDGetoptNoArgument },
+ { GBNoArg(kGBArgPublishDocSet), 0, DDGetoptNoArgument },
+ { kGBArgKeepIntermediateFiles, 0, DDGetoptNoArgument },
{ kGBArgKeepUndocumentedObjects, 0, DDGetoptNoArgument },
{ kGBArgKeepUndocumentedMembers, 0, DDGetoptNoArgument },
{ kGBArgFindUndocumentedMembersDocumentation, 0, DDGetoptNoArgument },
+ { kGBArgRepeatFirstParagraph, 0, DDGetoptNoArgument },
{ kGBArgMergeCategoriesToClasses, 0, DDGetoptNoArgument },
{ kGBArgKeepMergedCategoriesSections, 0, DDGetoptNoArgument },
{ kGBArgPrefixMergedCategoriesSectionsWithCategoryName, 0, DDGetoptNoArgument },
+ { GBNoArg(kGBArgKeepIntermediateFiles), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgKeepUndocumentedObjects), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgKeepUndocumentedMembers), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgFindUndocumentedMembersDocumentation), 0, DDGetoptNoArgument },
+ { GBNoArg(kGBArgRepeatFirstParagraph), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgMergeCategoriesToClasses), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgKeepMergedCategoriesSections), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgPrefixMergedCategoriesSectionsWithCategoryName), 0, DDGetoptNoArgument },
@@ -222,10 +245,14 @@ - (void)application:(DDCliApplication *)app willParseOptions:(DDGetoptLongParser
{ kGBArgWarnOnMissingCompanyIdentifier, 0, DDGetoptNoArgument },
{ kGBArgWarnOnUndocumentedObject, 0, DDGetoptNoArgument },
{ kGBArgWarnOnUndocumentedMember, 0, DDGetoptNoArgument },
+ { kGBArgWarnOnInvalidCrossReference, 0, DDGetoptNoArgument },
+ { kGBArgWarnOnMissingMethodArgument, 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgWarnOnMissingOutputPath), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgWarnOnMissingCompanyIdentifier), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgWarnOnUndocumentedObject), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgWarnOnUndocumentedMember), 0, DDGetoptNoArgument },
+ { GBNoArg(kGBArgWarnOnInvalidCrossReference), 0, DDGetoptNoArgument },
+ { GBNoArg(kGBArgWarnOnMissingMethodArgument), 0, DDGetoptNoArgument },
{ kGBArgLogFormat, 0, DDGetoptRequiredArgument },
{ kGBArgVerbose, 0, DDGetoptRequiredArgument },
@@ -275,6 +302,7 @@ - (void)initializeGlobalSettingsAndValidateTemplates {
path = [appSupportPath stringByAppendingPathComponent:@"appledoc"];
if ([self validateTemplatesPath:path error:nil]) {
[self overrideSettingsWithGlobalSettingsFromPath:path];
+ self.settings.templatesPath = path;
self.templatesFound = YES;
return;
}
@@ -283,6 +311,7 @@ - (void)initializeGlobalSettingsAndValidateTemplates {
path = @"~/.appledoc";
if ([self validateTemplatesPath:path error:nil]) {
[self overrideSettingsWithGlobalSettingsFromPath:path];
+ self.settings.templatesPath = path;
self.templatesFound = YES;
return;
}
@@ -351,7 +380,7 @@ - (void)validateSettingsAndArguments:(NSArray *)arguments {
}
// Validate we have at least one argument specifying the path to the files to handle. Also validate all given paths are valid.
- if ([arguments count] == 0) [NSException raise:@"At least one argument is required"];
+ if ([arguments count] == 0) [NSException raise:@"At least one directory or file name path is required, use 'appledoc --help'"];
for (NSString *path in arguments) {
if (![self.fileManager fileExistsAtPath:path]) {
[NSException raise:@"Path or file '%@' doesn't exist!", path];
@@ -380,64 +409,18 @@ - (void)validateSettingsAndArguments:(NSArray *)arguments {
ddprintf(@"WARN: --%@ argument or global setting not given, but creating DocSet is enabled, will use '%@'!\n", kGBArgCompanyIdentifier, self.settings.companyIdentifier);
}
}
-}
-
-- (void)printSettingsAndArguments:(NSArray *)arguments {
-#define PRINT_BOOL(v) (v ? @"YES" : @"NO")
- // This is useful for debugging to see exact set of setting values that are going to be used for this session. Note that this is coupling command line switches to actual settings. Here it's just the opposite than DDCli callbacks.
- ddprintf(@"Running for files in locations:\n");
- for (NSString *path in arguments) ddprintf(@"- %@\n", path);
- ddprintf(@"\n");
-
- ddprintf(@"Settings used for this run:\n");
- ddprintf(@"--%@ = %@\n", kGBArgProjectName, self.settings.projectName);
- ddprintf(@"--%@ = %@\n", kGBArgProjectVersion, self.settings.projectVersion);
- ddprintf(@"--%@ = %@\n", kGBArgProjectCompany, self.settings.projectCompany);
- ddprintf(@"--%@ = %@\n", kGBArgCompanyIdentifier, self.settings.companyIdentifier);
- ddprintf(@"\n");
-
- ddprintf(@"--%@ = %@\n", kGBArgTemplatesPath, self.settings.templatesPath);
- ddprintf(@"--%@ = %@\n", kGBArgOutputPath, self.settings.outputPath);
- for (NSString *path in self.settings.ignoredPaths) ddprintf(@"--%@ = %@\n", kGBArgIgnorePath, path);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetInstallPath, self.settings.docsetInstallPath);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetUtilPath, self.settings.docsetUtilPath);
- ddprintf(@"\n");
-
- ddprintf(@"--%@ = %@\n", kGBArgDocSetBundleIdentifier, self.settings.docsetBundleIdentifier);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetBundleName, self.settings.docsetBundleName);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetDescription, self.settings.docsetDescription);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetCopyrightMessage, self.settings.docsetCopyrightMessage);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetFeedName, self.settings.docsetFeedName);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetFeedURL, self.settings.docsetFeedURL);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetFallbackURL, self.settings.docsetFallbackURL);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetPublisherIdentifier, self.settings.docsetPublisherIdentifier);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetPublisherName, self.settings.docsetPublisherName);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetMinimumXcodeVersion, self.settings.docsetMinimumXcodeVersion);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetPlatformFamily, self.settings.docsetPlatformFamily);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetCertificateIssuer, self.settings.docsetCertificateIssuer);
- ddprintf(@"--%@ = %@\n", kGBArgDocSetCertificateSigner, self.settings.docsetCertificateSigner);
- ddprintf(@"\n");
- ddprintf(@"--%@ = %@\n", kGBArgCreateHTML, PRINT_BOOL(self.settings.createHTML));
- ddprintf(@"--%@ = %@\n", kGBArgCreateDocSet, PRINT_BOOL(self.settings.createDocSet));
- ddprintf(@"--%@ = %@\n", kGBArgInstallDocSet, PRINT_BOOL(self.settings.installDocSet));
- ddprintf(@"--%@ = %@\n", kGBArgKeepUndocumentedObjects, PRINT_BOOL(self.settings.keepUndocumentedObjects));
- ddprintf(@"--%@ = %@\n", kGBArgKeepUndocumentedMembers, PRINT_BOOL(self.settings.keepUndocumentedMembers));
- ddprintf(@"--%@ = %@\n", kGBArgFindUndocumentedMembersDocumentation, PRINT_BOOL(self.settings.findUndocumentedMembersDocumentation));
- ddprintf(@"--%@ = %@\n", kGBArgMergeCategoriesToClasses, PRINT_BOOL(self.settings.mergeCategoriesToClasses));
- ddprintf(@"--%@ = %@\n", kGBArgKeepMergedCategoriesSections, PRINT_BOOL(self.settings.keepMergedCategoriesSections));
- ddprintf(@"--%@ = %@\n", kGBArgPrefixMergedCategoriesSectionsWithCategoryName, PRINT_BOOL(self.settings.prefixMergedCategoriesSectionsWithCategoryName));
- ddprintf(@"\n");
+ // Make sure to switch on any setting thats required by "higher" level one.
+ if (self.settings.publishDocSet) self.settings.installDocSet = YES;
+ if (self.settings.installDocSet) self.settings.createDocSet = YES;
+ if (self.settings.createDocSet) self.settings.createHTML = YES;
+}
- ddprintf(@"--%@ = %@\n", kGBArgWarnOnMissingOutputPath, PRINT_BOOL(self.settings.warnOnMissingOutputPathArgument));
- ddprintf(@"--%@ = %@\n", kGBArgWarnOnMissingCompanyIdentifier, PRINT_BOOL(self.settings.warnOnMissingCompanyIdentifier));
- ddprintf(@"--%@ = %@\n", kGBArgWarnOnUndocumentedObject, PRINT_BOOL(self.settings.warnOnUndocumentedObject));
- ddprintf(@"--%@ = %@\n", kGBArgWarnOnUndocumentedMember, PRINT_BOOL(self.settings.warnOnUndocumentedMember));
- ddprintf(@"\n");
-
- ddprintf(@"--%@ = %@\n", kGBArgLogFormat, self.logformat);
- ddprintf(@"--%@ = %@\n", kGBArgVerbose, self.verbose);
- ddprintf(@"\n");
+- (NSString *)standardizeCurrentDirectoryForPath:(NSString *)path {
+ // Converts . to actual working directory.
+ if (![path hasPrefix:@"."] || [path hasPrefix:@".."]) return path;
+ NSString *suffix = [path substringFromIndex:1];
+ return [[self.fileManager currentDirectoryPath] stringByAppendingPathComponent:suffix];
}
#pragma mark Overriden methods
@@ -448,10 +431,10 @@ - (NSString *)description {
#pragma mark Callbacks API for DDCliApplication
-- (void)setOutput:(NSString *)path { self.settings.outputPath = path; }
-- (void)setTemplates:(NSString *)path { self.settings.templatesPath = path; }
-- (void)setDocsetInstallPath:(NSString *)path { self.settings.docsetInstallPath = path; }
-- (void)setDocsetutilPath:(NSString *)path { self.settings.docsetUtilPath = path; }
+- (void)setOutput:(NSString *)path { self.settings.outputPath = [self standardizeCurrentDirectoryForPath:path]; }
+- (void)setTemplates:(NSString *)path { self.settings.templatesPath = [self standardizeCurrentDirectoryForPath:path]; }
+- (void)setDocsetInstallPath:(NSString *)path { self.settings.docsetInstallPath = [self standardizeCurrentDirectoryForPath:path]; }
+- (void)setDocsetutilPath:(NSString *)path { self.settings.docsetUtilPath = [self standardizeCurrentDirectoryForPath:path]; }
- (void)setIgnore:(NSString *)path {
if ([path hasPrefix:@"*"]) path = [path substringFromIndex:1];
[self.settings.ignoredPaths addObject:path];
@@ -465,19 +448,25 @@ - (void)setCompanyId:(NSString *)value { self.settings.companyIdentifier = value
- (void)setCreateHtml:(BOOL)value { self.settings.createHTML = value; }
- (void)setCreateDocset:(BOOL)value { self.settings.createDocSet = value; }
- (void)setInstallDocset:(BOOL)value { self.settings.installDocSet = value; }
+- (void)setPublishDocset:(BOOL)value { self.settings.publishDocSet = value; }
- (void)setNoCreateHtml:(BOOL)value { self.settings.createHTML = !value; }
- (void)setNoCreateDocset:(BOOL)value { self.settings.createDocSet = !value; }
- (void)setNoInstallDocset:(BOOL)value { self.settings.installDocSet = !value; }
+- (void)setNoPublishDocset:(BOOL)value { self.settings.publishDocSet = !value; }
+- (void)setKeepIntermediateFiles:(BOOL)value { self.settings.keepIntermediateFiles = value;}
- (void)setKeepUndocumentedObjects:(BOOL)value { self.settings.keepUndocumentedObjects = value; }
- (void)setKeepUndocumentedMembers:(BOOL)value { self.settings.keepUndocumentedMembers = value; }
- (void)setSearchUndocumentedDoc:(BOOL)value { self.settings.findUndocumentedMembersDocumentation = value; }
+- (void)setRepeatFirstPar:(BOOL)value { self.settings.repeatFirstParagraphForMemberDescription = value; }
- (void)setMergeCategories:(BOOL)value { self.settings.mergeCategoriesToClasses = value; }
- (void)setKeepMergedSections:(BOOL)value { self.settings.keepMergedCategoriesSections = value; }
- (void)setPrefixMergedSections:(BOOL)value { self.settings.prefixMergedCategoriesSectionsWithCategoryName = value; }
+- (void)setNoKeepIntermediateFiles:(BOOL)value { self.settings.keepIntermediateFiles = !value;}
- (void)setNoKeepUndocumentedObjects:(BOOL)value { self.settings.keepUndocumentedObjects = !value; }
- (void)setNoKeepUndocumentedMembers:(BOOL)value { self.settings.keepUndocumentedMembers = !value; }
- (void)setNoSearchUndocumentedDoc:(BOOL)value { self.settings.findUndocumentedMembersDocumentation = !value; }
+- (void)setNoRepeatFirstPar:(BOOL)value { self.settings.repeatFirstParagraphForMemberDescription = !value; }
- (void)setNoMergeCategories:(BOOL)value { self.settings.mergeCategoriesToClasses = !value; }
- (void)setNoKeepMergedSections:(BOOL)value { self.settings.keepMergedCategoriesSections = !value; }
- (void)setNoPrefixMergedSections:(BOOL)value { self.settings.prefixMergedCategoriesSectionsWithCategoryName = !value; }
@@ -486,17 +475,22 @@ - (void)setWarnMissingOutputPath:(BOOL)value { self.settings.warnOnMissingOutput
- (void)setWarnMissingCompanyId:(BOOL)value { self.settings.warnOnMissingCompanyIdentifier = value; }
- (void)setWarnUndocumentedObject:(BOOL)value { self.settings.warnOnUndocumentedObject = value; }
- (void)setWarnUndocumentedMember:(BOOL)value { self.settings.warnOnUndocumentedMember = value; }
+- (void)setWarnInvalidCrossref:(BOOL)value { self.settings.warnOnInvalidCrossReference = value; }
+- (void)setWarnMissingArg:(BOOL)value { self.settings.warnOnMissingMethodArgument = value; }
- (void)setNoWarnMissingOutputPath:(BOOL)value { self.settings.warnOnMissingOutputPathArgument = !value; }
- (void)setNoWarnMissingCompanyId:(BOOL)value { self.settings.warnOnMissingCompanyIdentifier = !value; }
- (void)setNoWarnUndocumentedObject:(BOOL)value { self.settings.warnOnUndocumentedObject = !value; }
- (void)setNoWarnUndocumentedMember:(BOOL)value { self.settings.warnOnUndocumentedMember = !value; }
+- (void)setNoWarnInvalidCrossref:(BOOL)value { self.settings.warnOnInvalidCrossReference = !value; }
+- (void)setNoWarnMissingArg:(BOOL)value { self.settings.warnOnMissingMethodArgument = !value; }
- (void)setDocsetBundleId:(NSString *)value { self.settings.docsetBundleIdentifier = value; }
- (void)setDocsetBundleName:(NSString *)value { self.settings.docsetBundleName = value; }
- (void)setDocsetDesc:(NSString *)value { self.settings.docsetDescription = value; }
- (void)setDocsetCopyright:(NSString *)value { self.settings.docsetCopyrightMessage = value; }
- (void)setDocsetFeedName:(NSString *)value { self.settings.docsetFeedName = value; }
- (void)setDocsetFeedUrl:(NSString *)value { self.settings.docsetFeedURL = value; }
+- (void)setDocsetPackageUrl:(NSString *)value { self.settings.docsetPackageURL = value; }
- (void)setDocsetFallbackUrl:(NSString *)value { self.settings.docsetFallbackURL = value; }
- (void)setDocsetPublisherId:(NSString *)value { self.settings.docsetPublisherIdentifier = value; }
- (void)setDocsetPublisherName:(NSString *)value { self.settings.docsetPublisherName = value; }
@@ -505,6 +499,10 @@ - (void)setDocsetPlatformFamily:(NSString *)value { self.settings.docsetPlatform
- (void)setDocsetCertIssuer:(NSString *)value { self.settings.docsetCertificateIssuer = value; }
- (void)setDocsetCertSigner:(NSString *)value { self.settings.docsetCertificateSigner = value; }
+- (void)setDocsetBundleFilename:(NSString *)value { self.settings.docsetBundleFilename = value; }
+- (void)setDocsetAtomFilename:(NSString *)value { self.settings.docsetAtomFilename = value; }
+- (void)setDocsetPackageFilename:(NSString *)value { self.settings.docsetPackageFilename = value; }
+
@synthesize logformat;
@synthesize verbose;
@synthesize printSettings;
@@ -522,10 +520,76 @@ - (void)setDocsetCertSigner:(NSString *)value { self.settings.docsetCertificateS
@implementation GBAppledocApplication (UsagePrintout)
+- (void)printSettingsAndArguments:(NSArray *)arguments {
+#define PRINT_BOOL(v) (v ? @"YES" : @"NO")
+ // This is useful for debugging to see exact set of setting values that are going to be used for this session. Note that this is coupling command line switches to actual settings. Here it's just the opposite than DDCli callbacks.
+ ddprintf(@"Running for files in locations:\n");
+ for (NSString *path in arguments) ddprintf(@"- %@\n", path);
+ ddprintf(@"\n");
+
+ ddprintf(@"Settings used for this run:\n");
+ ddprintf(@"--%@ = %@\n", kGBArgProjectName, self.settings.projectName);
+ ddprintf(@"--%@ = %@\n", kGBArgProjectVersion, self.settings.projectVersion);
+ ddprintf(@"--%@ = %@\n", kGBArgProjectCompany, self.settings.projectCompany);
+ ddprintf(@"--%@ = %@\n", kGBArgCompanyIdentifier, self.settings.companyIdentifier);
+ ddprintf(@"\n");
+
+ ddprintf(@"--%@ = %@\n", kGBArgTemplatesPath, self.settings.templatesPath);
+ ddprintf(@"--%@ = %@\n", kGBArgOutputPath, self.settings.outputPath);
+ for (NSString *path in self.settings.ignoredPaths) ddprintf(@"--%@ = %@\n", kGBArgIgnorePath, path);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetInstallPath, self.settings.docsetInstallPath);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetUtilPath, self.settings.docsetUtilPath);
+ ddprintf(@"\n");
+
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetBundleIdentifier, self.settings.docsetBundleIdentifier);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetBundleName, self.settings.docsetBundleName);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetDescription, self.settings.docsetDescription);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetCopyrightMessage, self.settings.docsetCopyrightMessage);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetFeedName, self.settings.docsetFeedName);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetFeedURL, self.settings.docsetFeedURL);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetPackageURL, self.settings.docsetPackageURL);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetFallbackURL, self.settings.docsetFallbackURL);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetPublisherIdentifier, self.settings.docsetPublisherIdentifier);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetPublisherName, self.settings.docsetPublisherName);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetMinimumXcodeVersion, self.settings.docsetMinimumXcodeVersion);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetPlatformFamily, self.settings.docsetPlatformFamily);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetCertificateIssuer, self.settings.docsetCertificateIssuer);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetCertificateSigner, self.settings.docsetCertificateSigner);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetBundleFilename, self.settings.docsetBundleFilename);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetAtomFilename, self.settings.docsetAtomFilename);
+ ddprintf(@"--%@ = %@\n", kGBArgDocSetPackageFilename, self.settings.docsetPackageFilename);
+ ddprintf(@"\n");
+
+ ddprintf(@"--%@ = %@\n", kGBArgCreateHTML, PRINT_BOOL(self.settings.createHTML));
+ ddprintf(@"--%@ = %@\n", kGBArgCreateDocSet, PRINT_BOOL(self.settings.createDocSet));
+ ddprintf(@"--%@ = %@\n", kGBArgInstallDocSet, PRINT_BOOL(self.settings.installDocSet));
+ ddprintf(@"--%@ = %@\n", kGBArgPublishDocSet, PRINT_BOOL(self.settings.publishDocSet));
+ ddprintf(@"--%@ = %@\n", kGBArgKeepIntermediateFiles, PRINT_BOOL(self.settings.keepIntermediateFiles));
+ ddprintf(@"--%@ = %@\n", kGBArgKeepUndocumentedObjects, PRINT_BOOL(self.settings.keepUndocumentedObjects));
+ ddprintf(@"--%@ = %@\n", kGBArgKeepUndocumentedMembers, PRINT_BOOL(self.settings.keepUndocumentedMembers));
+ ddprintf(@"--%@ = %@\n", kGBArgFindUndocumentedMembersDocumentation, PRINT_BOOL(self.settings.findUndocumentedMembersDocumentation));
+ ddprintf(@"--%@ = %@\n", kGBArgRepeatFirstParagraph, PRINT_BOOL(self.settings.repeatFirstParagraphForMemberDescription));
+ ddprintf(@"--%@ = %@\n", kGBArgMergeCategoriesToClasses, PRINT_BOOL(self.settings.mergeCategoriesToClasses));
+ ddprintf(@"--%@ = %@\n", kGBArgKeepMergedCategoriesSections, PRINT_BOOL(self.settings.keepMergedCategoriesSections));
+ ddprintf(@"--%@ = %@\n", kGBArgPrefixMergedCategoriesSectionsWithCategoryName, PRINT_BOOL(self.settings.prefixMergedCategoriesSectionsWithCategoryName));
+ ddprintf(@"\n");
+
+ ddprintf(@"--%@ = %@\n", kGBArgWarnOnMissingOutputPath, PRINT_BOOL(self.settings.warnOnMissingOutputPathArgument));
+ ddprintf(@"--%@ = %@\n", kGBArgWarnOnMissingCompanyIdentifier, PRINT_BOOL(self.settings.warnOnMissingCompanyIdentifier));
+ ddprintf(@"--%@ = %@\n", kGBArgWarnOnUndocumentedObject, PRINT_BOOL(self.settings.warnOnUndocumentedObject));
+ ddprintf(@"--%@ = %@\n", kGBArgWarnOnUndocumentedMember, PRINT_BOOL(self.settings.warnOnUndocumentedMember));
+ ddprintf(@"\n");
+
+ ddprintf(@"--%@ = %@\n", kGBArgLogFormat, self.logformat);
+ ddprintf(@"--%@ = %@\n", kGBArgVerbose, self.verbose);
+ ddprintf(@"\n");
+}
+
- (void)printVersion {
NSString *appledocName = [self.settings.stringTemplates.appledocData objectForKey:@"tool"];
NSString *appledocVersion = [self.settings.stringTemplates.appledocData objectForKey:@"version"];
- ddprintf(@"%@ version: %@\n", appledocName, appledocVersion);
+ NSString *appledocBuild = [self.settings.stringTemplates.appledocData objectForKey:@"build"];
+ ddprintf(@"%@ version: %@ (build %@)\n", appledocName, appledocVersion, appledocBuild);
ddprintf(@"\n");
}
@@ -547,23 +611,28 @@ - (void)printHelp {
PRINT_USAGE(@" ", kGBArgCompanyIdentifier, @"<string>", @"Company UTI (i.e. reverse DNS name)");
ddprintf(@"\n");
ddprintf(@"OUTPUT GENERATION\n");
- PRINT_USAGE(@"-h,", kGBArgCreateHTML, @"<bool>", @"Create HTML");
- PRINT_USAGE(@"-d,", kGBArgCreateDocSet, @"<bool>", @"Create HTML and documentation set");
- PRINT_USAGE(@"-n,", kGBArgInstallDocSet, @"<bool>", @"Create HTML & DocSet and install DocSet to Xcode");
+ PRINT_USAGE(@"-h,", kGBArgCreateHTML, @"", @"[b] Create HTML");
+ PRINT_USAGE(@"-d,", kGBArgCreateDocSet, @"", @"[b] Create documentation set");
+ PRINT_USAGE(@"-n,", kGBArgInstallDocSet, @"", @"[b] Install documentation set to Xcode");
+ PRINT_USAGE(@"-u,", kGBArgPublishDocSet, @"", @"[b] Prepare DocSet for publishing");
ddprintf(@"\n");
ddprintf(@"OPTIONS\n");
- PRINT_USAGE(@" ", kGBArgKeepUndocumentedObjects, @"<bool>", @"Keep undocumented objects");
- PRINT_USAGE(@" ", kGBArgKeepUndocumentedMembers, @"<bool>", @"Keep undocumented members");
- PRINT_USAGE(@" ", kGBArgFindUndocumentedMembersDocumentation, @"<bool>", @"Search undocumented members documentation");
- PRINT_USAGE(@" ", kGBArgMergeCategoriesToClasses, @"<bool>", @"Merge categories to classes");
- PRINT_USAGE(@" ", kGBArgKeepMergedCategoriesSections, @"<bool>", @"Keep merged categories sections");
- PRINT_USAGE(@" ", kGBArgPrefixMergedCategoriesSectionsWithCategoryName, @"<bool>", @"Prefix merged sections with category name");
+ PRINT_USAGE(@" ", kGBArgKeepIntermediateFiles, @"", @"[b] Keep intermediate files in output path");
+ PRINT_USAGE(@" ", kGBArgKeepUndocumentedObjects, @"", @"[b] Keep undocumented objects");
+ PRINT_USAGE(@" ", kGBArgKeepUndocumentedMembers, @"", @"[b] Keep undocumented members");
+ PRINT_USAGE(@" ", kGBArgFindUndocumentedMembersDocumentation, @"", @"[b] Search undocumented members documentation");
+ PRINT_USAGE(@" ", kGBArgRepeatFirstParagraph, @"", @"[b] Repeat first paragraph in member documentation");
+ PRINT_USAGE(@" ", kGBArgMergeCategoriesToClasses, @"", @"[b] Merge categories to classes");
+ PRINT_USAGE(@" ", kGBArgKeepMergedCategoriesSections, @"", @"[b] Keep merged categories sections");
+ PRINT_USAGE(@" ", kGBArgPrefixMergedCategoriesSectionsWithCategoryName, @"", @"[b] Prefix merged sections with category name");
ddprintf(@"\n");
ddprintf(@"WARNINGS\n");
- PRINT_USAGE(@" ", kGBArgWarnOnMissingOutputPath, @"<bool>", @"Warn if output path is not given");
- PRINT_USAGE(@" ", kGBArgWarnOnMissingCompanyIdentifier, @"<bool>", @"Warn if company ID is not given");
- PRINT_USAGE(@" ", kGBArgWarnOnUndocumentedObject, @"<bool>", @"Warn on undocumented object");
- PRINT_USAGE(@" ", kGBArgWarnOnUndocumentedMember, @"<bool>", @"Warn on undocumented member");
+ PRINT_USAGE(@" ", kGBArgWarnOnMissingOutputPath, @"", @"[b] Warn if output path is not given");
+ PRINT_USAGE(@" ", kGBArgWarnOnMissingCompanyIdentifier, @"", @"[b] Warn if company ID is not given");
+ PRINT_USAGE(@" ", kGBArgWarnOnUndocumentedObject, @"", @"[b] Warn on undocumented object");
+ PRINT_USAGE(@" ", kGBArgWarnOnUndocumentedMember, @"", @"[b] Warn on undocumented member");
+ PRINT_USAGE(@" ", kGBArgWarnOnInvalidCrossReference, @"", @"[b] Warn on invalid cross reference");
+ PRINT_USAGE(@" ", kGBArgWarnOnMissingMethodArgument, @"", @"[b] Warn on missing method argument documentation");
ddprintf(@"\n");
ddprintf(@"DOCUMENTATION SET INFO\n");
PRINT_USAGE(@" ", kGBArgDocSetBundleIdentifier, @"<string>", @"[*] DocSet bundle identifier");
@@ -572,28 +641,46 @@ - (void)printHelp {
PRINT_USAGE(@" ", kGBArgDocSetCopyrightMessage, @"<string>", @"[*] DocSet copyright message");
PRINT_USAGE(@" ", kGBArgDocSetFeedName, @"<string>", @"[*] DocSet feed name");
PRINT_USAGE(@" ", kGBArgDocSetFeedURL, @"<string>", @"[*] DocSet feed URL");
+ PRINT_USAGE(@" ", kGBArgDocSetPackageURL, @"<string>", @"[*] DocSet package (.xar) URL");
PRINT_USAGE(@" ", kGBArgDocSetFallbackURL, @"<string>", @"[*] DocSet fallback URL");
PRINT_USAGE(@" ", kGBArgDocSetPublisherIdentifier, @"<string>", @"[*] DocSet publisher identifier");
PRINT_USAGE(@" ", kGBArgDocSetPublisherName, @"<string>", @"[*] DocSet publisher name");
PRINT_USAGE(@" ", kGBArgDocSetMinimumXcodeVersion, @"<string>", @"[*] DocSet min. Xcode version");
PRINT_USAGE(@" ", kGBArgDocSetPlatformFamily, @"<string>", @"[*] DocSet platform familiy");
PRINT_USAGE(@" ", kGBArgDocSetCertificateIssuer, @"<string>", @"[*] DocSet certificate issuer");
PRINT_USAGE(@" ", kGBArgDocSetCertificateSigner, @"<string>", @"[*] DocSet certificate signer");
+ PRINT_USAGE(@" ", kGBArgDocSetBundleFilename, @"<string>", @"[*] DocSet bundle filename");
+ PRINT_USAGE(@" ", kGBArgDocSetAtomFilename, @"<string>", @"[*] DocSet atom feed filename");
+ PRINT_USAGE(@" ", kGBArgDocSetPackageFilename, @"<string>", @"[*] DocSet package (.xar) filename");
ddprintf(@"\n");
ddprintf(@"MISCELLANEOUS\n");
PRINT_USAGE(@" ", kGBArgLogFormat, @"<number>", @"Log format [0-3]");
PRINT_USAGE(@" ", kGBArgVerbose, @"<number>", @"Log verbosity level [0-6]");
PRINT_USAGE(@" ", kGBArgVersion, @"", @"Display version and exit");
PRINT_USAGE(@" ", kGBArgHelp, @"", @"Display this help and exit");
ddprintf(@"\n");
+ ddprintf(@"==================================================================\n");
+ ddprintf(@"[b] boolean parameter, uses no value, use --no- prefix to negate.\n");
+ ddprintf(@"\n");
ddprintf(@"[*] indicates parameters accepting placeholder strings:\n");
- ddprintf(@"- $PROJECT replaced with --project-name\n");
- ddprintf(@"- $VERSION replaced with --project-version\n");
- ddprintf(@"- $COMPANY replaced with --project-company\n");
- ddprintf(@"- $COMPANYID replaced with --company-id\n");
- ddprintf(@"- $YEAR replaced with current year (format yyyy)\n");
- ddprintf(@"- $UPDATEDATE replaced with current date (format yyyy-MM-dd)\n");
+ ddprintf(@"- %%PROJECT replaced with --project-name\n");
+ ddprintf(@"- %%PROJECTID replaced with normalized --project-name\n");
+ ddprintf(@"- %%VERSION replaced with --project-version\n");
+ ddprintf(@"- %%VERSIONID replaced with normalized --project-version\n");
+ ddprintf(@"- %%COMPANY replaced with --project-company\n");
+ ddprintf(@"- %%COMPANYID replaced with --company-id\n");
+ ddprintf(@"- %%YEAR replaced with current year (format yyyy)\n");
+ ddprintf(@"- %%UPDATEDATE replaced with current date (format yyyy-MM-dd)\n");
+ ddprintf(@"- %%DOCSETBUNDLEFILENAME replaced with --docset-bundle-filename\n");
+ ddprintf(@"- %%DOCSETATOMFILENAME replaced with --docset-atom-filename\n");
+ ddprintf(@"- %%DOCSETPACKAGEFILENAME replaced with --docset-package-filename\n");
+ ddprintf(@"\n");
+ ddprintf(@"==================================================================\n");
+ ddprintf(@"Find more help and tips online:\n");
+ ddprintf(@"- http://appledoc.gentlebytes.com/\n");
+ ddprintf(@"- http://tomaz.github.com/appledoc/\n");
ddprintf(@"\n");
+ ddprintf(@"==================================================================\n");
ddprintf(@"%@ uses the following open source components, fully or partially:\n", name);
ddprintf(@"\n");
ddprintf(@"- DDCli by Dave Dribin\n");
View
131 Application/GBApplicationSettingsProvider.h
@@ -14,8 +14,24 @@
/** Main application settings provider.
This object implements `GBApplicationStringsProviding` interface and is used by `GBAppledocApplication` to prepare application-wide settings including factory defaults, global and session values. The main purpose of the class is to simplify `GBAppledocApplication` class by decoupling it from the actual settings providing implementation.
+
+ To create a new setting use the following check list to update `GBApplicationSettingsProvider`:
+
+ 1. Create the property here (don't forget about `@synthetize`!).
+ 2. Set default value in initializer.
+
+ If the setting should be mapped to command line switch also do the following in `GBAppledocApplication`:
+
+ 1. Create a new global string as `static NSString` containing the command line switch name.
+ 2. Register the switch to `DDCli` (add negated switch if it's a boolean).
+ 3. Add unit test in `GBAppledocApplicationTesting.m` that validates the switch is properly mapped to setting property (note that boolean swithces require testing normal and negated variants!).
+ 4. Add KVC setter and map to corresponding property to make the test pass (again booleans require two setters).
+ 5. If the switch value uses template placeholders, add unit test in `GBApplicationSettingsProviderTesting.m` that validates the switch is handled.
+ 6. If previous point was used, add the code to `replaceAllOccurencesOfPlaceholderStringsInSettingsValues` to make the test pass.
+ 7. Add the switch value printout to `printSettingsAndArguments:`.
+ 8. Add the switch help printout to `printHelp`.
*/
-@interface GBApplicationSettingsProvider : NSObject <NSCopying>
+@interface GBApplicationSettingsProvider : NSObject
///---------------------------------------------------------------------------------------
/// @name Initialization & disposal
@@ -41,6 +57,12 @@
/** Company unique identifier, ussualy in the form of reverse domain like _com.company_. */
@property (copy) NSString *companyIdentifier;
+/** Project identifier which is derived by normalizing `projectName`. */
+@property (readonly) NSString *projectIdentifier;
+
+/** Version identifier which is derived by normalizing `projectVersion`. */
+@property (readonly) NSString *versionIdentifier;
+
///---------------------------------------------------------------------------------------
/// @name Documentation set handling
///---------------------------------------------------------------------------------------
@@ -69,6 +91,9 @@
/** Documentation set feed URL. */
@property (copy) NSString *docsetFeedURL;
+/** Documentation set package URL. */
+@property (copy) NSString *docsetPackageURL;
+
/** Documentation set minimum Xcode version. */
@property (copy) NSString *docsetMinimumXcodeVersion;
@@ -84,6 +109,15 @@
/** Documentation set human readble copyright message. */
@property (copy) NSString *docsetCopyrightMessage;
+/** The name of the documentation set installed bundle. The folder is generated in `docsetInstallPath`. */
+@property (copy) NSString *docsetBundleFilename;
+
+/** The name of the documentation set atom file when generating publishing files. The file is generated in `outputPath`. */
+@property (copy) NSString *docsetAtomFilename;
+
+/** The name of the documentation set compressed package file when generating publishing files. The file is generated in `outputPath`. */
+@property (copy) NSString *docsetPackageFilename;
+
///---------------------------------------------------------------------------------------
/// @name Paths handling
///---------------------------------------------------------------------------------------
@@ -110,6 +144,54 @@
/// @name Behavior handling
///---------------------------------------------------------------------------------------
+/* Indicates whether HTML files should be generated or not.
+
+ If `YES`, HTML files are generated in `outputPath` from parsed and processed data. If `NO`, input files are parsed and processed, but nothing is generated.
+
+ @see createDocSet
+ */
+@property (assign) BOOL createHTML;
+
+/** Specifies whether documentation set should be created from the HTML files.
+
+ If `YES`, HTML files from html subdirectory in `outputPath` are moved to proper subdirectory within docset output files, then helper files are generated from parsed data. Documentation set files are also indexed. If `NO`, HTML files are left in the output path.
+
+ @see createHtml
+ @see installDocSet
+ @see publishDocSet
+ */
+@property (assign) BOOL createDocSet;
+
+/** Specifies whether the documentation set should be installed or not.
+
+ If `YES`, temporary files used for indexing and removed, then documentation set bundle is created from the files from docset output path and is moved to `docsetInstallPath`. If `NO`, all documentation set files are left in output path.
+
+ @see createDocSet
+ @see publishDocSet
+ */
+@property (assign) BOOL installDocSet;
+
+/** Specifies whether the documentation set should be prepared for publishing or not.
+
+ If `YES`, installed documentation set is packaged for publishing - an atom feed is created and documentation set is archived. If the atom feed file is alreay found, it is updated with new information. Both, the feed and archived docset files are located within `outputPath`. If `NO`, documentation set is not prepared for publishing.
+
+ @see createDocSet
+ @see installDocSet
+ */
+@property (assign) BOOL publishDocSet;
+
+/** Specifies whether intermediate files should be kept in `outputPath` or not.
+
+ If `YES`, all intermediate files (i.e. HTML files and documentation set files) are kept in output path. If `NO`, only final results are kept. This setting not only affects how the files are being handled, it also affects performance. If intermediate files are not kept, appledoc moves files between various generation phases, otherwise it copies them. So it's prefferable to leave this option to `NO`. This option only affects output files, input source files are always left intact!
+ */
+@property (assign) BOOL keepIntermediateFiles;
+
+/** Indicates whether the first paragraph needs to be repeated within method and property description or not.
+
+ If `YES`, first paragraph is repeated in members description, otherwise not.
+ */
+@property (assign) BOOL repeatFirstParagraphForMemberDescription;
+
/* Indicates whether undocumented classes, categories or protocols should be kept or ignored when generating output.
If `YES` undocumented objects are kept and are used for output generation. If `NO`, these objects are ignored, but only if all their members are also not documented - as soon as a single member is documented, the object is included in output together with all of it's documented members.
@@ -186,31 +268,6 @@
*/
@property (assign) BOOL prefixMergedCategoriesSectionsWithCategoryName;
-/* Indicates whether HTML files should be generated or not.
-
- If `YES`, HTML files are generated in `outputPath` from parsed and processed data. If `NO`, input files are parsed and processed, but nothing is generated.
-
- @see createDocSet
- */
-@property (assign) BOOL createHTML;
-
-/** Specifies whether documentation set should be created from the HTML files.
-
- If `YES`, HTML files from html subdirectory in `outputPath` are moved to proper subdirectory within docset output files, then helper files are generated from parsed data. Documentation set files are also indexed. If `NO`, HTML files are left in the output path.
-
- @see createHtml
- @see installDocSet
- */
-@property (assign) BOOL createDocSet;
-
-/** Specifies whether the documentation set should be installed or not.
-
- If `YES`, temporary files used for indexing and removed, then documentation set bundle is created from the files from docset output path and is moved to `docsetInstallPath`. If `NO`, all documentation set files are left in output path.
-
- @see createDocSet
- */
-@property (assign) BOOL installDocSet;
-
///---------------------------------------------------------------------------------------
/// @name Warnings handling
///---------------------------------------------------------------------------------------
@@ -243,6 +300,12 @@
*/
@property (assign) BOOL warnOnUndocumentedMember;
+/** Indicates whether invalid cross reference should result in warning or not. */
+@property (assign) BOOL warnOnInvalidCrossReference;
+
+/** Indicates whether missing method argument descriptions in comments should result in warnings or not. */
+@property (assign) BOOL warnOnMissingMethodArgument;
+
///---------------------------------------------------------------------------------------
/// @name Application-wide HTML helpers
///---------------------------------------------------------------------------------------
@@ -316,11 +379,17 @@
This method provides application-wide string placeholders replacement functionality. It replaces all known placeholders with actual values from the receiver. Placeholders are identified by a dollar mark, followed by placeholder name. The following placeholders are supported (note that case is important!):
- - `$PROJECT`: Replaced by `projectName` value.
- - `$COMPANY`: Replaced by `projectCompany` value.
- - `$VERSION`: Replaced by `projectVersion` value.
- - `$YEAR`: Replaced by current year as four digit string.
- - `$UPDATEDATE`: Replaced by current date in the form of year, month and day with format `YYYY-MM-DD`. For example `2010-11-30`.
+ - `%PROJECT`: Replaced by `projectName` value.
+ - `%PROJECTID`: Replaced by `projectIdentifier` value.
+ - `%COMPANY`: Replaced by `projectCompany` value.
+ - `%COMPANYID`: Replaced by `companyIdentifier` value.
+ - `%VERSION`: Replaced by `projectVersion` value.
+ - `%VERSIONID`: Replaced by `versionIdentifier` value.
+ - `%DOCSETBUNDLEFILENAME`: Replaced by `docsetBundleFilename` value.
+ - `%DOCSETATOMFILENAME`: Replaced by `docsetAtomFilename` value.
+ - `%DOCSETPACKAGEFILENAME`: Replaced by `docsetPackageFilename` value.
+ - `%YEAR`: Replaced by current year as four digit string.
+ - `%UPDATEDATE`: Replaced by current date in the form of year, month and day with format `YYYY-MM-DD`. For example `2010-11-30`.
@param string The string to replace placeholder occurences in.
@return Returns new string with all placeholder occurences replaced.
View
110 Application/GBApplicationSettingsProvider.m
@@ -7,6 +7,7 @@
//
#import <objc/runtime.h>
+#import "RegexKitLite.h"
#import "GBDataObjects.h"
#import "GBApplicationSettingsProvider.h"
@@ -18,6 +19,7 @@ - (NSString *)relativePathPrefixFromObject:(GBModelBase *)source toObject:(GBMod
- (NSString *)htmlReferenceForObjectFromIndex:(GBModelBase *)object;
- (NSString *)htmlReferenceForTopLevelObject:(GBModelBase *)object fromTopLevelObject:(GBModelBase *)source;
- (NSString *)htmlReferenceForMember:(GBModelBase *)member prefixedWith:(NSString *)prefix;
+- (NSString *)stringByNormalizingString:(NSString *)string;
@property (readonly) NSDateFormatter *yearDateFormatter;
@property (readonly) NSDateFormatter *yearToDayDateFormatter;
@@ -53,7 +55,10 @@ - (id)init {
self.createHTML = YES;
self.createDocSet = YES;
- self.installDocSet = NO;
+ self.installDocSet = YES;
+ self.publishDocSet = NO;
+ self.repeatFirstParagraphForMemberDescription = YES;
+ self.keepIntermediateFiles = NO;
self.keepUndocumentedObjects = NO;
self.keepUndocumentedMembers = NO;
self.findUndocumentedMembersDocumentation = YES;
@@ -65,51 +70,42 @@ - (id)init {
self.warnOnMissingCompanyIdentifier = YES;
self.warnOnUndocumentedObject = YES;
self.warnOnUndocumentedMember = YES;
+ self.warnOnInvalidCrossReference = YES;
+ self.warnOnMissingMethodArgument = YES;
- self.docsetBundleIdentifier = @"$COMPANYID.$PROJECT";
- self.docsetBundleName = @"$PROJECT Documentation";
+ self.docsetBundleIdentifier = @"%COMPANYID.%PROJECTID";
+ self.docsetBundleName = @"%PROJECT Documentation";
self.docsetCertificateIssuer = @"";
self.docsetCertificateSigner = @"";
self.docsetDescription = @"";
self.docsetFallbackURL = @"";
- self.docsetFeedName = @"";
+ self.docsetFeedName = self.docsetBundleName;
self.docsetFeedURL = @"";
+ self.docsetPackageURL = @"";
self.docsetMinimumXcodeVersion = @"3.0";
self.docsetPlatformFamily = @"";
- self.docsetPublisherIdentifier = @"$COMPANYID.documentation";
- self.docsetPublisherName = @"$COMPANY";
- self.docsetCopyrightMessage = @"© $YEAR $COMPANY. All rights reserved.";
+ self.docsetPublisherIdentifier = @"%COMPANYID.documentation";
+ self.docsetPublisherName = @"%COMPANY";
+ self.docsetCopyrightMessage = @"Copyright © %YEAR %COMPANY. All rights reserved.";
+
+ self.docsetBundleFilename = @"%COMPANYID.%PROJECTID.docset";
+ self.docsetAtomFilename = @"%COMPANYID.%PROJECTID.atom";
+ self.docsetPackageFilename = @"%COMPANYID.%PROJECTID-%VERSIONID.xar";
self.commentComponents = [GBCommentComponentsProvider provider];
self.stringTemplates = [GBApplicationStringsProvider provider];
}
return self;
}
-- (id)copyWithZone:(NSZone *)zone {
- // This uses reflection to get the list of all properties and then KVC to copy the values from this object to the copy, skipping helper classes to keep
- NSSet *ignored = [[self class] nonCopyableProperties];
- id result = [[[[self class] alloc] init] autorelease];
- unsigned int count;
- objc_property_t *properties = class_copyPropertyList([self class], &count);
- for (unsigned int i=0; i<count; i++) {
- objc_property_t property = properties[i];
- const char *name = property_getName(property);
- if (!name) continue;
-
- NSString *key = [NSString stringWithCString:name encoding:NSASCIIStringEncoding];
- if ([ignored containsObject:key]) continue;
-
- id value = [self valueForKey:key];
- [result setValue:value forKey:key];
- }
- free(properties);
- return result;
-}
-
#pragma mark Helper methods
- (void)replaceAllOccurencesOfPlaceholderStringsInSettingsValues {
+ // These need to be replaced first as they can be used in other settings!
+ self.docsetBundleFilename = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetBundleFilename];
+ self.docsetAtomFilename = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetAtomFilename];
+ self.docsetPackageFilename = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetPackageFilename];
+ // Handle the rest now.
self.docsetBundleIdentifier = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetBundleIdentifier];
self.docsetBundleName = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetBundleName];
self.docsetCertificateIssuer = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetCertificateIssuer];
@@ -118,6 +114,7 @@ - (void)replaceAllOccurencesOfPlaceholderStringsInSettingsValues {
self.docsetFallbackURL = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetFallbackURL];
self.docsetFeedName = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetFeedName];
self.docsetFeedURL = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetFeedURL];
+ self.docsetPackageURL = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetPackageURL];
self.docsetMinimumXcodeVersion = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetMinimumXcodeVersion];
self.docsetPlatformFamily = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetPlatformFamily];
self.docsetPublisherIdentifier = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetPublisherIdentifier];
@@ -269,23 +266,58 @@ - (BOOL)isTopLevelStoreObject:(id)object {
}
- (NSString *)stringByReplacingOccurencesOfPlaceholdersInString:(NSString *)string {
- string = [string stringByReplacingOccurrencesOfString:@"$COMPANYID" withString:self.companyIdentifier];
- string = [string stringByReplacingOccurrencesOfString:@"$PROJECT" withString:self.projectName];
- string = [string stringByReplacingOccurrencesOfString:@"$COMPANY" withString:self.projectCompany];
- string = [string stringByReplacingOccurrencesOfString:@"$VERSION" withString:self.projectVersion];
- string = [string stringByReplacingOccurrencesOfString:@"$YEAR" withString:[self yearStringFromDate:[NSDate date]]];
- string = [string stringByReplacingOccurrencesOfString:@"$UPDATEDATE" withString:[self yearToDayStringFromDate:[NSDate date]]];
+ string = [string stringByReplacingOccurrencesOfString:@"%COMPANYID" withString:self.companyIdentifier];
+ string = [string stringByReplacingOccurrencesOfString:@"%PROJECTID" withString:self.projectIdentifier];
+ string = [string stringByReplacingOccurrencesOfString:@"%VERSIONID" withString:self.versionIdentifier];
+ string = [string stringByReplacingOccurrencesOfString:@"%PROJECT" withString:self.projectName];
+ string = [string stringByReplacingOccurrencesOfString:@"%COMPANY" withString:self.projectCompany];
+ string = [string stringByReplacingOccurrencesOfString:@"%VERSION" withString:self.projectVersion];
+ string = [string stringByReplacingOccurrencesOfString:@"%DOCSETBUNDLEFILENAME" withString:self.docsetBundleFilename];
+ string = [string stringByReplacingOccurrencesOfString:@"%DOCSETATOMFILENAME" withString:self.docsetAtomFilename];
+ string = [string stringByReplacingOccurrencesOfString:@"%DOCSETPACKAGEFILENAME" withString:self.docsetPackageFilename];
+ string = [string stringByReplacingOccurrencesOfString:@"%YEAR" withString:[self yearStringFromDate:[NSDate date]]];
+ string = [string stringByReplacingOccurrencesOfString:@"%UPDATEDATE" withString:[self yearToDayStringFromDate:[NSDate date]]];
return string;
}
+- (NSString *)stringByNormalizingString:(NSString *)string {
+ return [string stringByReplacingOccurrencesOfRegex:@"[ \t]+" withString:@"-"];
+}
+
#pragma mark Overriden methods
- (NSString *)description {
return [self className];
}
+- (NSString *)debugDescription {
+ // Based on http://stackoverflow.com/questions/754824/get-an-object-attributes-list-in-objective-c/4008326#4008326
+ NSMutableString *result = [NSMutableString string];
+ unsigned int outCount, i;
+ objc_property_t *properties = class_copyPropertyList([self class], &outCount);
+ for (i=0; i<outCount; i++) {
+ objc_property_t property = properties[i];
+ const char *propName = property_getName(property);
+ if (propName) {
+ NSString *propertyName = [NSString stringWithUTF8String:propName];
+ NSString *propertyValue = [self valueForKey:propertyName];
+ [result appendFormat:@"%@ = %@\n", propertyName, propertyValue];
+ }
+ }
+ free(properties);
+ return result;
+}
+
#pragma mark Properties
+- (NSString *)projectIdentifier {
+ return [self stringByNormalizingString:self.projectName];
+}
+
+- (NSString *)versionIdentifier {
+ return [self stringByNormalizingString:self.projectVersion];
+}
+
@synthesize projectName;
@synthesize projectCompany;
@synthesize projectVersion;
@@ -305,12 +337,18 @@ - (NSString *)description {
@synthesize docsetFallbackURL;
@synthesize docsetFeedName;
@synthesize docsetFeedURL;
+@synthesize docsetPackageURL;
@synthesize docsetMinimumXcodeVersion;
@synthesize docsetPlatformFamily;
@synthesize docsetPublisherIdentifier;
@synthesize docsetPublisherName;
@synthesize docsetCopyrightMessage;
+@synthesize docsetBundleFilename;
+@synthesize docsetAtomFilename;
+@synthesize docsetPackageFilename;
+
+@synthesize repeatFirstParagraphForMemberDescription;
@synthesize keepUndocumentedObjects;
@synthesize keepUndocumentedMembers;
@synthesize findUndocumentedMembersDocumentation;
@@ -322,11 +360,15 @@ - (NSString *)description {
@synthesize createHTML;
@synthesize createDocSet;
@synthesize installDocSet;
+@synthesize publishDocSet;
+@synthesize keepIntermediateFiles;
@synthesize warnOnMissingOutputPathArgument;
@synthesize warnOnMissingCompanyIdentifier;
@synthesize warnOnUndocumentedObject;
@synthesize warnOnUndocumentedMember;
+@synthesize warnOnInvalidCrossReference;
+@synthesize warnOnMissingMethodArgument;
@synthesize commentComponents;
@synthesize stringTemplates;
View
3 Application/GBApplicationStringsProvider.m
@@ -124,7 +124,8 @@ - (NSDictionary *)appledocData {
if (!result) {
result = [[NSMutableDictionary alloc] init];
[result setObject:@"appledoc" forKey:@"tool"];
- [result setObject:@"2.0b3" forKey:@"version"];
+ [result setObject:@"2.0" forKey:@"version"];
+ [result setObject:@"514" forKey:@"build"];
[result setObject:@"http://appledoc.gentlebytes.com" forKey:@"homepage"];
}
return result;
View
25 Application/GBCommentComponentsProvider.h
@@ -29,15 +29,9 @@
/** Returns the regex used for matching ordered lists with capture 1 containing lists indent and capture 2 string value. */
@property (readonly) NSString *orderedListRegex;
-/** Returns the regex used for testing whether a string matches an ordered lists. */
-@property (readonly) NSString *orderedListMatchRegex;
-
/** Returns the regex used for matching unordered lists with capture 1 containing list indent and capture 2 string value. */
@property (readonly) NSString *unorderedListRegex;
-/** Returns the regex used for testing whether a string matches an unordered list. */
-@property (readonly) NSString *unorderedListMatchRegex;
-
///---------------------------------------------------------------------------------------
/// @name Sections definitions
///---------------------------------------------------------------------------------------
@@ -48,12 +42,9 @@
/** Returns the regex used for matching bug section with capture 1 containing description. */
@property (readonly) NSString *bugSectionRegex;
-/** Returns the regex used for matching example section with capture 1 containing example text. */
+/** Returns the regex used for matching example section with capture 1 containing whitespace prefix and capture 2 example text. */
@property (readonly) NSString *exampleSectionRegex;
-/** Returns the regex used for matching example lines with capture 1 containing example lines texts. */
-@property (readonly) NSString *exampleLinesRegex;
-
///---------------------------------------------------------------------------------------
/// @name Method specific definitions
///---------------------------------------------------------------------------------------
@@ -80,7 +71,7 @@
@property (readonly) NSString *crossReferenceRegex;
///---------------------------------------------------------------------------------------
-/// @name Common definitions
+/// @name Cross references definitions
///---------------------------------------------------------------------------------------
/** Returns the regex used for matching (possible) remote member cross references with capture 1 containing object name and capture 2 member name. */
@@ -89,10 +80,20 @@
/** Returns the regex used for matching (possible) local member cross reference with capture 1 containing member name. */
@property (readonly) NSString *localMemberCrossReferenceRegex;
-/** Returns the regex used for matching (possible) object cross reference with capture 1 containing object name. */
+/** Returns the regex used for matching (possible) category cross reference with capture 1 containing category name. */
+@property (readonly) NSString *categoryCrossReferenceRegex;
+
+/** Returns the regex used for matching (possible) class or protocol cross reference with capture 1 containing object name. */
@property (readonly) NSString *objectCrossReferenceRegex;
/** Returns the regex used for matching URL cross reference with caption 1 contining the URL itself. */
@property (readonly) NSString *urlCrossReferenceRegex;
+///---------------------------------------------------------------------------------------
+/// @name Common definitions
+///---------------------------------------------------------------------------------------
+
+/** Returns the regex containing all possible symbols for matching new lines. */
+@property (readonly) NSString *newLineRegex;
+
@end
View
50 Application/GBCommentComponentsProvider.m
@@ -19,10 +19,8 @@
@interface GBCommentComponentsProvider ()
- (NSString *)argumentsCommonRegex;
-- (NSString *)exampleRegexWithoutFlags;
- (NSString *)descriptionCaptureRegexForKeyword:(NSString *)keyword;
- (NSString *)nameDescriptionCaptureRegexForKeyword:(NSString *)keyword;
-- (NSString *)crossReferenceRegexByEmbeddingRegex:(NSString *)regex;
@end
@@ -39,19 +37,11 @@ + (id)provider {
#pragma mark Lists detection
- (NSString *)orderedListRegex {
- GBRETURN_ON_DEMAND(([NSString stringWithFormat:@"(?m:%@(.*))", self.orderedListMatchRegex]));
+ GBRETURN_ON_DEMAND(@"^([ \\t]*)[0-9]+\\.\\s+(?s:(.*))");
}
- (NSString *)unorderedListRegex {
- GBRETURN_ON_DEMAND(([NSString stringWithFormat:@"(?m:%@(.*))", self.unorderedListMatchRegex]));
-}
-
-- (NSString *)orderedListMatchRegex {
- GBRETURN_ON_DEMAND(@"^([ \\t]*)[0-9]+\\.\\s+");
-}
-
-- (NSString *)unorderedListMatchRegex {
- GBRETURN_ON_DEMAND(@"^([ \\t]*)[-+*]\\s+");
+ GBRETURN_ON_DEMAND(@"^([ \\t]*)[-+*]\\s+(?s:(.*))");
}
#pragma mark Sections detection
@@ -65,15 +55,7 @@ - (NSString *)bugSectionRegex {
}
- (NSString *)exampleSectionRegex {
- GBRETURN_ON_DEMAND(([NSString stringWithFormat:@"(?s:%@)", [self exampleRegexWithoutFlags]]));
-}
-
-- (NSString *)exampleLinesRegex {
- GBRETURN_ON_DEMAND(([NSString stringWithFormat:@"(?m:%@)", [self exampleRegexWithoutFlags]]));
-}
-
-- (NSString *)exampleRegexWithoutFlags {
- GBRETURN_ON_DEMAND(@"^[ ]*\\t(.*)");
+ GBRETURN_ON_DEMAND(@"^( ?\\t| )(.*)$");
}
#pragma mark Method specific detection
@@ -110,23 +92,33 @@ - (NSString *)crossReferenceRegex {
GBRETURN_ON_DEMAND([self descriptionCaptureRegexForKeyword:@"(?:sa|see)"]);
}
-#pragma mark Common detection
+#pragma mark Cross references detection
- (NSString *)remoteMemberCrossReferenceRegex {
// +[Class member] or -[Class member] or simply [Class member].
- return [self crossReferenceRegexByEmbeddingRegex:@"[+-]?\\[(\\S+)\\s+(\\S+)\\]"];
+ return @"<?[+-]?\\[(\\S+)\\s+(\\S+)\\]>?";
}
- (NSString *)localMemberCrossReferenceRegex {
- return [self crossReferenceRegexByEmbeddingRegex:@"([^>\\s]+)"];
+ return @"<?([^>,.;!?()\\s]+)>?";
+}
+
+- (NSString *)categoryCrossReferenceRegex {
+ return @"<?([^(][^>,.:;!?)\\s]+\\))>?";
}
- (NSString *)objectCrossReferenceRegex {
- return [self crossReferenceRegexByEmbeddingRegex:@"([^>\\s]+)"];
+ return @"<?([^>,.:;!?()\\s]+)>?";
}
- (NSString *)urlCrossReferenceRegex {
- return [self crossReferenceRegexByEmbeddingRegex:@"(((?:(?:http|https|ftp|file)://)|(?:mailto:))[^>\\s]*)"];
+ return @"<?(\\b(?:mailto\\:|(?:https?|ftps?|news|rss|file)\\://)[a-zA-Z0-9@:\\-.]+(?::(\\d+))?(?:(?:/[a-zA-Z0-9\\-._?,'+\\&%$=~*!():@\\\\]*)+)?)>?";
+}
+
+#pragma mark Common detection
+
+- (NSString *)newLineRegex {
+ GBRETURN_ON_DEMAND([NSString stringWithUTF8String:"\\r\\n|[\\n\\v\\f\\r\302\205\\p{Zl}\\p{Zp}]+"]);
}
#pragma mark Helper methods
@@ -136,11 +128,7 @@ - (NSString *)descriptionCaptureRegexForKeyword:(NSString *)keyword {
}
- (NSString *)nameDescriptionCaptureRegexForKeyword:(NSString *)keyword {
- return [NSString stringWithFormat:@"^\\s*\\S%@\\s+([^\\s]+)\\s+(?s:(.*))", keyword];
-}
-
-- (NSString *)crossReferenceRegexByEmbeddingRegex:(NSString *)regex {
- return [NSString stringWithFormat:@"<?%@>?", regex];
+ return [NSString stringWithFormat:@"^\\s*\\S%@\\s+(\\S+)\\s+(?s:(.*))", keyword];
}
@end
View
1 Common/GBTask.m
@@ -151,6 +151,7 @@ - (NSArray *)linesFromString:(NSString *)string {
@synthesize reportBlock;
@synthesize reportIndividualLines;
+@synthesize lastCommandLine;
@synthesize lastStandardOutput;
@synthesize lastStandardError;
View
58 Common/NSArray+GBArray.h
@@ -0,0 +1,58 @@
+//
+// NSArray+GBArray.h
+// appledoc
+//
+// Created by Tomaz Kragelj on 13.1.11.
+// Copyright 2011 Gentle Bytes. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/** Provides extensions to `NSArray` for simpler handling. */
+@interface NSArray (GBArray)
+
+/** Returns the first object in the receiver.
+
+ If array is empty, `nil` is returned.
+
+ @return Returns the first object in the receiver.
+ */
+- (id)firstObject;
+
+/** Determines if the receiver is an empty array.
+
+ @return Returns `YES` if the receiver is an empty array, `NO` otherwise.
+ */
+- (BOOL)isEmpty;
+
+@end
+
+/** Provides extensions to `NSMutableArray` for simpler handling. */
+@interface NSMutableArray (GBMutableArray)
+
+/** Helper method for adding the given object to the end of the receiver.
+
+ Internally the method sends the receiver `addObject:`, but using this method makes usage of array as stack more obvious.
+
+ @param object The object to push to the end of the receiver.
+ */
+- (void)push:(id)object;
+
+/** Helper method to removing the last object from the receiver.
+
+ Internally the method sends the receiver `removeLastObject` and returns the removed object. If receiver is an empty array, exception is raised.
+
+ @return Returns the object removed from the receiver.
+ @exception NSException Raised if the receiver is an empty array.
+ */
+- (id)pop;
+
+/** Helper method for looking at the last object in the receiver.
+
+ Internally, the method sends the receiver `lastObject` message and returns the result. If the receiver is an empty array, `nil` is returned.
+
+ @return Returns the last object in the receiver.
+ */
+- (id)peek;
+
+@end
View
42 Common/NSArray+GBArray.m
@@ -0,0 +1,42 @@
+//
+// NSArray+GBArray.m
+// appledoc
+//
+// Created by Tomaz Kragelj on 13.1.11.
+// Copyright 2011 Gentle Bytes. All rights reserved.
+//
+
+#import "NSArray+GBArray.h"
+
+@implementation NSArray (GBArray)
+
+- (id)firstObject {
+ if ([self count] == 0) return nil;
+ return [self objectAtIndex:0];
+}
+
+- (BOOL)isEmpty {
+ return ([self count] == 0);
+}
+
+@end
+
+#pragma mark -
+
+@implementation NSMutableArray (GBMutableArray)
+
+- (void)push:(id)object {
+ [self addObject:object];
+}
+
+- (id)pop {
+ id result = [self peek];
+ [self removeLastObject];
+ return result;
+}
+
+- (id)peek {
+ return [self lastObject];
+}
+
+@end
View
15 Common/NSString+GBString.h
@@ -78,6 +78,21 @@
/// @name Getting information
///---------------------------------------------------------------------------------------
+/** Creates a new `NSString` composed from all given lines delimited with the given delimiter.
+
+ @param lines Array of lines to combine.
+ @param delimiter Delimiter to use to separate lines.
+ @return Returns autoreleased string containing all lines.
+ */
++ (NSString *)stringByCombiningLines:(NSArray *)lines delimitWith:(NSString *)delimiter;
+
+/** Returns the array of all lines in the receiver.
+
+ @return Returns the array of all lines.
+ @see numberOfLines
+ */
+- (NSArray *)arrayOfLines;
+
/** Returns the number of all lines in the receiver.
@return Returns the number of all lines in the receiver.
View
24 Common/NSString+GBString.m
@@ -95,6 +95,30 @@ + (NSUInteger)defaultNormalizedDescriptionLength {
#pragma mark Getting information
++ (NSString *)stringByCombiningLines:(NSArray *)lines delimitWith:(NSString *)delimiter {
+ NSMutableString *result = [NSMutableString string];
+ if (!delimiter) delimiter = @"";
+ [lines enumerateObjectsUsingBlock:^(NSString *line, NSUInteger idx, BOOL *stop) {
+ if ([result length] > 0) [result appendString:delimiter];
+ [result appendString:line];
+ }];
+ return result;
+}
+
+- (NSArray *)arrayOfLines {
+ // Although we could use regex here, this gives us nicer results (strips all newlines for example), taken straight from Apple String Programming Guide.
+ NSMutableArray *result = [NSMutableArray array];
+ NSUInteger length = [self length];
+ NSUInteger paraStart = 0, paraEnd = 0, contentsEnd = 0;
+ NSRange currentRange;
+ while (paraEnd < length) {
+ [self getParagraphStart:&paraStart end:&paraEnd contentsEnd:&contentsEnd forRange:NSMakeRange(paraEnd, 0)];
+ currentRange = NSMakeRange(paraStart, contentsEnd - paraStart);
+ [result addObject:[self substringWithRange:currentRange]];
+ }
+ return result;
+}
+
- (NSUInteger)numberOfLines {
if ([self length] == 0) return 0;
return [self numberOfLinesInRange:NSMakeRange(0, [self length])];
View
115 Generating/GBDocSetOutputGenerator.m
@@ -16,13 +16,14 @@
@interface GBDocSetOutputGenerator ()
-- (BOOL)moveSourceFilesToDocuments:(NSError **)error;
+- (BOOL)copyOrMoveSourceFilesToDocuments:(NSError **)error;
- (BOOL)processInfoPlist:(NSError **)error;
- (BOOL)processNodesXml:(NSError **)error;
- (BOOL)processTokensXml:(NSError **)error;
- (BOOL)indexDocSet:(NSError **)error;
- (BOOL)removeTemporaryFiles:(NSError **)error;
- (BOOL)installDocSet:(NSError **)error;
+- (BOOL)publishDocSet:(NSError **)error;
- (BOOL)processTokensXmlForObjects:(NSArray *)objects type:(NSString *)type template:(NSString *)template index:(NSUInteger *)index error:(NSError **)error;
- (void)addTokensXmlModelObjectDataForObject:(GBModelBase *)object toData:(NSMutableDictionary *)data;
- (void)initializeSimplifiedObjects;
@@ -31,6 +32,7 @@ - (NSString *)tokenIdentifierForObject:(GBModelBase *)object;
@property (retain) NSArray *classes;
@property (retain) NSArray *categories;
@property (retain) NSArray *protocols;
+@property (readonly) NSString *docsetInstallationPath;
@property (readonly) NSMutableSet *temporaryFiles;
@end
@@ -50,20 +52,24 @@ - (BOOL)generateOutputWithStore:(id)store error:(NSError **)error {
[self initializeSimplifiedObjects];
// Create documentation set from files generated by previous generator.
- if (![self moveSourceFilesToDocuments:error]) return NO;
+ if (![self copyOrMoveSourceFilesToDocuments:error]) return NO;
if (![self processInfoPlist:error]) return NO;
if (![self processNodesXml:error]) return NO;
if (![self processTokensXml:error]) return NO;
if (![self indexDocSet:error]) return NO;
+ if (![self removeTemporaryFiles:error]) return NO;
// Install documentation set to Xcode.
if (!self.settings.installDocSet) return YES;
- if (![self removeTemporaryFiles:error]) return NO;
if (![self installDocSet:error]) return NO;
+
+ // Prepare documentation set for publishing.
+ if (!self.settings.publishDocSet) return YES;
+ if (![self publishDocSet:error]) return NO;
return YES;
}
-- (BOOL)moveSourceFilesToDocuments:(NSError **)error {
+- (BOOL)copyOrMoveSourceFilesToDocuments:(NSError **)error {
GBLogInfo(@"Moving HTML files to DocSet bundle...");
// Prepare all paths. Note that we determine the exact subdirectory by searching for documents-template and using it's subdirectory as the guide. If documents template wasn't found, exit.
@@ -75,10 +81,9 @@ - (BOOL)moveSourceFilesToDocuments:(NSError **)error {
return NO;
}
- // First step is to move all files generated by previous generator as the Documents subfolder of docset structure.
- NSString *movePath = [documentsPath stringByAppendingPathComponent:@"Documents"];
- if (![self.fileManager moveItemAtPath:sourceFilesPath toPath:[movePath stringByStandardizingPath] error:error]) {
- GBLogWarn(@"Failed moving files from '%@' to '%@'!", self.previousGenerator.outputUserPath, movePath);
+ // Copy or move all files generated by previous generator to documents subfolder of docset structure.
+ if (![self copyOrMoveItemFromPath:sourceFilesPath toPath:documentsPath error:error]) {
+ GBLogWarn(@"Failed moving files from '%@' to '%@'!", self.previousGenerator.outputUserPath, documentsPath);
return NO;
}
return YES;
@@ -193,7 +198,8 @@ - (BOOL)indexDocSet:(NSError **)error {
}
- (BOOL)removeTemporaryFiles:(NSError **)error {
- // We delete all registered temporary files and clear the list. If there are some problems, we simply log but always return YES - if these files remain, documentation set is still usable, so it's no point of aborting...
+ // We delete all registered temporary files and clear the list. If there are some problems, we simply log but always return YES - if these files remain, documentation set is still usable, so it's no point of aborting... Note that we keep all intermediate files if user has specified so.
+ if (self.settings.keepIntermediateFiles) return YES;
GBLogInfo(@"Removing temporary DocSet files...");
NSError *err = nil;
for (NSString *filename in self.temporaryFiles) {
@@ -208,30 +214,19 @@ - (BOOL)removeTemporaryFiles:(NSError **)error {
- (BOOL)installDocSet:(NSError **)error {
GBLogInfo(@"Installing DocSet...");
- // Prepare destination directory path and documentation set name.
- NSString *destDir = self.settings.docsetInstallPath;
- NSString *destSubDir = [self.settings.docsetBundleIdentifier stringByAppendingPathExtension:@"docset"];
-
// Prepare source and destination paths and file names.
NSString *sourceUserPath = self.outputUserPath;
- NSString *destUserPath = [destDir stringByAppendingPathComponent:destSubDir];
+ NSString *destUserPath = self.docsetInstallationPath;
NSString *sourcePath = [sourceUserPath stringByStandardizingPath];
- NSString *destPath = [destUserPath stringByStandardizingPath];
+ NSString *destPath = [destUserPath stringByStandardizingPath];\
- // Create destination directory and move files to it. If the destination directory alredy exists, remove it. Then create installation directory to make sure it's there the first time. Then move the docset files to the correct subdirectory.
+ // Create destination directory and move files to it.
GBLogVerbose(@"Moving DocSet files from '%@' to '%@'...", sourceUserPath, destUserPath);
- if ([self.fileManager fileExistsAtPath:destPath]) {
- GBLogDebug(@"Removing previous DocSet installation directory '%@'...", destUserPath);
- if (![self.fileManager removeItemAtPath:destPath error:error]) {
- GBLogWarn(@"Failed removing previous DocSet installation directory '%@'!", destUserPath);
- return NO;
- }
- }
- if (![self.fileManager createDirectoryAtPath:[destDir stringByStandardizingPath] withIntermediateDirectories:YES attributes:nil error:error]) {
- GBLogWarn(@"Failed creating DocSet installation parent directory '%@'!", destDir);
+ if (![self initializeDirectoryAtPath:destUserPath error:error]) {
+ GBLogWarn(@"Failed initializing DocSet installation directory '%@'!", destUserPath);
return NO;
}
- if (![self.fileManager moveItemAtPath:sourcePath toPath:destPath error:error]) {
+ if (![self copyOrMoveItemFromPath:sourcePath toPath:destPath error:error]) {
GBLogWarn(@"Failed moving DocSet files from '%@' to '%@'!", sourceUserPath, destUserPath);
return NO;
}
@@ -255,6 +250,58 @@ - (BOOL)installDocSet:(NSError **)error {
return YES;
}
+- (BOOL)publishDocSet:(NSError **)error {
+ GBLogInfo(@"Preparing DocSet for publishing...");
+ GBTask *task = [GBTask task];
+ task.reportIndividualLines = YES;
+
+ // Get the path to the installed documentation set and extract the name. Then replace the name's extension with .xar.
+ NSString *installedDocSetPath = self.docsetInstallationPath;
+ NSString *packageName = self.settings.docsetPackageFilename;
+ NSString *atomName = self.settings.docsetAtomFilename;
+
+ // Prepare command line arguments for packaging.
+ NSString *outputDir = [self.settings.outputPath stringByAppendingPathComponent:@"publish"];
+ NSString *outputDocSetPath = [outputDir stringByAppendingPathComponent:packageName];
+ NSString *outputAtomPath = [outputDir stringByAppendingPathComponent:atomName];
+ NSString *signer = self.settings.docsetCertificateSigner;
+ NSString *url = self.settings.docsetPackageURL;
+ if ([url length] == 0) GBLogWarn(@"--docset-package-url is required for publishing DocSet; placeholder will be used in '%@'!", outputAtomPath);
+
+ // Create destination directory.
+ if (![self initializeDirectoryAtPath:outputDir preserve:[NSArray arrayWithObject:atomName] error:error]) {
+ GBLogWarn(@"Failed initializing DocSet publish directory '%@'!", outputDir);
+ return NO;
+ }
+
+ // Create command line arguments array.
+ NSMutableArray *args = [NSMutableArray array];
+ [args addObject:@"package"];
+ [args addObject:@"-output"];
+ [args addObject:[outputDocSetPath stringByStandardizingPath]];
+ [args addObject:@"-atom"];
+ [args addObject:[outputAtomPath stringByStandardizingPath]];
+ if ([signer length] > 0) {
+ [args addObject:@"-signid"];
+ [args addObject:signer];
+ }
+ if ([url length] > 0) {
+ [args addObject:@"-download-url"];
+ [args addObject:url];
+ }
+ [args addObject:installedDocSetPath];
+
+ BOOL result = [task runCommand:self.settings.docsetUtilPath arguments:args block:^(NSString *output, NSString *error) {
+ if (output) GBLogDebug(@"> %@", [output stringByTrimmingWhitespaceAndNewLine]);
+ if (error) GBLogError(@"!> %@", [error stringByTrimmingWhitespaceAndNewLine]);
+ }];
+ if (!result) {
+ if (error) *error = [NSError errorWithCode:GBErrorDocSetUtilIndexingFailed description:@"docsetutil failed to package the documentation set!" reason:task.lastStandardError];
+ return NO;
+ }
+ return YES;
+}
+
#pragma mark Helper methods
- (BOOL)processTokensXmlForObjects:(NSArray *)objects type:(NSString *)type template:(NSString *)template index:(NSUInteger *)index error:(NSError **)error {
@@ -391,12 +438,6 @@ - (NSArray *)simplifiedObjectsFromObjects:(NSArray *)objects value:(NSString *)v
return result;
}
-- (NSMutableSet *)temporaryFiles {
- static NSMutableSet *result = nil;
- if (!result) result = [[NSMutableSet alloc] init];
- return result;
-}
-
#pragma mark Overriden methods
- (NSString *)outputSubpath {
@@ -405,6 +446,16 @@ - (NSString *)outputSubpath {
#pragma mark Properties
+- (NSString *)docsetInstallationPath {
+ return [self.settings.docsetInstallPath stringByAppendingPathComponent:self.settings.docsetBundleFilename];
+}
+
+- (NSMutableSet *)temporaryFiles {
+ static NSMutableSet *result = nil;
+ if (!result) result = [[NSMutableSet alloc] init];
+ return result;
+}
+
@synthesize classes;
@synthesize categories;
@synthesize protocols;
View
14 Generating/GBHTMLOutputGenerator.m
@@ -158,18 +158,8 @@ - (BOOL)validateTemplates:(NSError **)error {
#pragma mark Helper methods
- (NSString *)stringByCleaningHtml:(NSString *)string {
- NSString *result = [string stringByReplacingOccurrencesOfString:@" " withString:@" "];
- result = [result stringByReplacingOccurrencesOfString:@"<code> " withString:@"<code>"];
- result = [result stringByReplacingOccurrencesOfString:@" </code>" withString:@"</code>"];
- result = [result stringByReplacingOccurrencesOfString:@"<pre> " withString:@"<pre>"];
- result = [result stringByReplacingOccurrencesOfString:@" </pre>" withString:@"</pre>"];
- while (YES) {
- NSString *source = [result stringByMatching:@"</code> [],.!?:;'\")}>]"];
- if (!source) break;
- NSString *replacement = [source stringByReplacingOccurrencesOfString:@" " withString:@""];
- result = [result stringByReplacingOccurrencesOfString:source withString:replacement];
- }
- return result;
+ // Nothing to do at this point - as we're preserving all whitespace, we should be just fine with generated string. The method is still left as a placeholder for possible future handling.
+ return string;
}
- (NSString *)htmlOutputPathForIndex {
View
4 Generating/GBHTMLTemplateVariablesProvider.m
@@ -186,8 +186,8 @@ - (NSDictionary *)arrayDescriptorForArray:(NSArray *)array {
- (void)addFooterVarsToDictionary:(NSMutableDictionary *)dict {
[dict setObject:self.settings.projectCompany forKey:@"copyrightHolder"];
- [dict setObject:[self.settings stringByReplacingOccurencesOfPlaceholdersInString:@"$YEAR"] forKey:@"copyrightDate"];
- [dict setObject:[self.settings stringByReplacingOccurencesOfPlaceholdersInString:@"$UPDATEDATE"] forKey:@"lastUpdatedDate"];
+ [dict setObject:[self.settings stringByReplacingOccurencesOfPlaceholdersInString:@"%YEAR"] forKey:@"copyrightDate"];
+ [dict setObject:[self.settings stringByReplacingOccurencesOfPlaceholdersInString:@"%UPDATEDATE"] forKey:@"lastUpdatedDate"];
}
#pragma mark Properties
View
31 Generating/GBOutputGenerator.h
@@ -43,6 +43,31 @@
/// @name Generation handling
///---------------------------------------------------------------------------------------
+/** Initializes the directory at the given path.
+
+ If the directory alreay exists, it is removed. Then a new one is created with all intermediate directories as needed. The result of the method is an empty directory at the given path. Sending this message has the same effect as sending `initializeDirectoryAtPath:preserve:error:` and passing `nil` for preserve argument.
+
+ @param path The path to initialize.
+ @param error If initialization fails, error is returned here.
+ @return Returns `YES` if initialization succeeds, `NO` otherwise.
+ @see initializeDirectoryAtPath:preserve:error:
+ */
+- (BOOL)initializeDirectoryAtPath:(NSString *)path error:(NSError **)error;
+
+/** Initializes the directory at the given path optionally preserving any number of files or subdirectories.
+
+ If the directory doesn't exist, it is created. Otherwise all files and subdirectories are removed, except for the given array of files or subdirectories to preserve. If the array is `nil` or empty, all files are removed. Preserve array should contain paths relative to the given path. The paths are not handled recursively - only first level items are preserved!
+
+ The result of the method is an empty directory at the given path containing only files or subdirectories from the given array.
+
+ @param path The path to initialize.
+ @param preserve An array of paths to preserve.
+ @param error If initialization fails, error is returned here.
+ @return Returns `YES` if initialization succeeds, `NO` otherwise.
+ @see initializeDirectoryAtPath:error:
+ */
+- (BOOL)initializeDirectoryAtPath:(NSString *)path preserve:(NSArray *)preserve error:(NSError **)error;
+
/** Copies all files from the templates path to the output path as defined in assigned `settings`, replicating the directory structure and stores all detected template files to `templateFiles` dictionary.
The method uses `[GBApplicationSettingsProvider templatesPath]` as the base path for templates and `[GBApplicationSettingsProvider outputPath]` as the base path for output. In both cases, `outputSubpath` is used to determine the source and destination subdirectories. It then copies all files from template path to the output path, including the whole directory structure. If any special template file is found at source path, it is not copied! Template files are identified by having a `-template` suffix followed by optional extension. For example `object-template.html`. As this message prepares the ground for actual generation, it should be sent before any other messages (i.e. before `generateOutput:`).
@@ -58,6 +83,12 @@
*/
- (BOOL)copyTemplateFilesToOutputPath:(NSError **)error;
+/** Copies or moves directory or file from the given source path to the destination path.
+
+ This method takes into account `[GBApplicationSettings keepIntermediateFiles]` and either copies or moves files regarding it's value. The method is designed to be used from within subclasses.
+ */
+- (BOOL)copyOrMoveItemFromPath:(NSString *)source toPath:(NSString *)destination error:(NSError **)error;
+
/** Generates the output at the proper subdirectory of the output path as defined in assigned `settings`.
This is the most important method of the `GBOutputGenerator` class. It generates all required output. It is intended to be overriden in subclasses. Default implementation assigns the given store and returns YES. Subclasses must call super class implementation before anything else!
View
68 Generating/GBOutputGenerator.m
@@ -68,6 +68,13 @@ - (BOOL)copyTemplateFilesToOutputPath:(NSError **)error {
}
}
+ // Create directory hierarchy minus the last one. This is necessary if more than one component is missing at destination path; copyItemAtPath:toPath:error would fail in such case. Note that we can't create the last directory as mentioned method request is that the destination doesn't exist!
+ NSString *createDestPath = [destPath stringByDeletingLastPathComponent];
+ if (![self.fileManager createDirectoryAtPath:createDestPath withIntermediateDirectories:YES attributes:nil error:error]) {
+ GBLogWarn(@"Failed creating directory '%@'!", createDestPath);
+ return NO;
+ }
+
// If there's no source file, there also no need to copy anything, so exit. In fact, copying would probably just result in errors.
if (![self.fileManager fileExistsAtPath:sourcePath]) {
GBLogDebug(@"No template file found at '%@', no need to copy.", sourceUserPath);
@@ -82,7 +89,7 @@ - (BOOL)copyTemplateFilesToOutputPath:(NSError **)error {
}
// Remove all ignored files and special template items from output. First enumerate all files. If this fails, report success; this step is only used to verscleanup the destination, we should still have valid output if these files are kept there.
- GBLogDebug(@"Removing leftovers from '%@'...", destUserPath);
+ GBLogDebug(@"Removing temporary files from '%@'...", destUserPath);
NSArray *items = [self.fileManager subpathsOfDirectoryAtPath:destPath error:error];
if (!items) {
GBLogWarn(@"Failed enumerating template files at '%@'!", destUserPath);
@@ -91,16 +98,17 @@ - (BOOL)copyTemplateFilesToOutputPath:(NSError **)error {
for (NSString *path in items) {
BOOL delete = NO;
if ([self isPathRepresentingIgnoredFile:path]) {
+ GBLogDebug(@"Removing ignored file '%@' from output...", path);
delete = YES;
} else if ([self isPathRepresentingTemplateFile:path]) {
GBTemplateHandler *handler = [self templateHandlerFromTemplateFile:path error:error];
if (!handler) return NO;
+ GBLogDebug(@"Removing template file '%@' from output...", path);
[self.templateFiles setObject:handler forKey:path];
delete = YES;
}
if (delete) {
- GBLogDebug(@"Cleaning leftover '%@' from output...", path);
NSString *fullpath = [destPath stringByAppendingPathComponent:path];
if (![self.fileManager removeItemAtPath:fullpath error:error]) {
GBLogWarn(@"Can't clean leftover '%@' from '%@'.", path, destUserPath);
@@ -111,6 +119,62 @@ - (BOOL)copyTemplateFilesToOutputPath:(NSError **)error {
return YES;
}
+- (BOOL)initializeDirectoryAtPath:(NSString *)path error:(NSError **)error {
+ return [self initializeDirectoryAtPath:path preserve:nil error:error];
+}
+
+- (BOOL)initializeDirectoryAtPath:(NSString *)path preserve:(NSArray *)preserve error:(NSError **)error {
+ GBLogVerbose(@"Initializing directory at '%@'...", path);
+ NSString *standardized = [path stringByStandardizingPath];
+
+ // If no path is to be preserved, just use simple approach of removing path and recreating it later on... Otherwise delete all content except given one.
+ BOOL exists = [self.fileManager fileExistsAtPath:standardized];
+ if ([preserve count] == 0) {
+ if (exists) {
+ GBLogDebug(@"Removing existing directory...");
+ if (![self.fileManager removeItemAtPath:standardized error:error]) return NO;
+ }
+ } else if (exists) {
+ GBLogDebug(@"Enumerating directory contents...");
+ NSArray *contents = [self.fileManager contentsOfDirectoryAtPath:path error:error];
+ if (!contents && error && *error) return NO;
+ for (NSString *subpath in contents) {
+ if (![preserve containsObject:subpath]) {
+ GBLogDebug(@"Removing '%@'...", subpath);
+ if (![self.fileManager removeItemAtPath:[path stringByAppendingPathComponent:subpath] error:error]) return NO;
+ }
+ }
+ }
+
+ // Create the directory if it doesn't yet exist. Note that we rely on system to actually check if the directory exists, instead of the cached value from above. The cached value may change if we remove the directory. Although we could change the value too, it makes tool safer this way.
+ if (![self.fileManager fileExistsAtPath:standardized]) {
+ GBLogDebug(@"Creating directory...");
+ return [self.fileManager createDirectoryAtPath:standardized withIntermediateDirectories:YES attributes:nil error:error];
+ }
+ return YES;
+}
+
+- (BOOL)copyOrMoveItemFromPath:(NSString *)source toPath:(NSString *)destination error:(NSError **)error {
+ BOOL copy = self.settings.keepIntermediateFiles;
+ GBLogDebug(@"%@ '%@' to '%@'...", copy ? @"Copying" : @"Moving", source, destination);
+
+ NSString *standardSource = [source stringByStandardizingPath];
+ NSString *standardDest = [destination stringByStandardizingPath];
+
+ // We must first delete destination path if it exists. Otherwise copy or move will fail!
+ if ([self.fileManager fileExistsAtPath:standardDest]) {
+ GBLogDebug(@"Removing '%@'...", destination);
+ if (![self.fileManager removeItemAtPath:standardDest error:error]) {
+ GBLogWarn(@"Failed removing '%@'!", destination);
+ return NO;
+ }
+ }
+
+ // Now either copy or move.
+ if (copy) return [self.fileManager copyItemAtPath:standardSource toPath:standardDest error:error];
+ return [self.fileManager moveItemAtPath:source toPath:destination error:error];
+}
+
- (BOOL)isPathRepresentingTemplateFile:(NSString *)path {
NSString *filename = [[path lastPathComponent] stringByDeletingPathExtension];
if ([filename hasSuffix:@"-template"]) return YES;
View
13 Model/GBAdoptedProtocolsProvider.m
@@ -78,6 +78,19 @@ - (NSString *)description {
return [_parent description];
}
+- (NSString *)debugDescription {
+ NSMutableString *result = [NSMutableString string];
+ if ([self.protocols count] > 0) {
+ [result appendString:@"<"];
+ [[self protocolsSortedByName] enumerateObjectsUsingBlock:^(GBProtocolData *protocol, NSUInteger idx, BOOL *stop) {
+ if (idx > 0) [result appendString:@", "];
+ [result appendString:protocol.nameOfProtocol];
+ }];
+ [result appendString:@">"];
+ }
+ return result;
+}
+
#pragma mark Properties
@synthesize protocols = _protocols;
View
4 Model/GBCategoryData.m
@@ -49,6 +49,10 @@ - (NSString *)description {
return self.idOfCategory;
}
+- (NSString *)debugDescription {
+ return [NSString stringWithFormat:@"category %@ %@\n%@", self.idOfCategory, self.adoptedProtocols.debugDescription, self.methods.debugDescription];
+}
+
- (BOOL)isTopLevelObject {
return YES;
}
View
6 Model/GBClassData.m
@@ -44,7 +44,7 @@ - (void)mergeDataFromObject:(id)source {
if (![self nameOfSuperclass]) {
self.nameOfSuperclass = sourceClass.nameOfSuperclass;
} else if (sourceClass.nameOfSuperclass && ![self.nameOfSuperclass isEqualToString:sourceClass.nameOfSuperclass]) {
- GBLogWarn(@"%@: Merged class's %@ superclass is different from ours!", self, sourceClass);
+ GBLogWarn(@"%@: Merged class's %@ superclass is different from current!", self, sourceClass);
}
// Forward merging request to components.
@@ -57,6 +57,10 @@ - (NSString *)description {
return self.nameOfClass;
}
+- (NSString *)debugDescription {
+ return [NSString stringWithFormat:@"class %@ %@\n%@", self.nameOfClass, self.adoptedProtocols.debugDescription, self.methods.debugDescription];
+}
+
- (BOOL)isTopLevelObject {
return YES;
}
View
36 Model/GBComment.h
@@ -32,6 +32,7 @@
@interface GBComment : NSObject {
@private
NSMutableArray *_paragraphs;
+ NSMutableArray *_descriptionParagraphs;
NSMutableArray *_parameters;
NSMutableArray *_exceptions;
NSMutableArray *_crossrefs;
@@ -83,6 +84,7 @@
@see registerParagraph:
@see paragraphs
+ @see descriptionParagraphs
*/
@property (retain) GBCommentParagraph *firstParagraph;
@@ -91,6 +93,7 @@
The paragraphs are in same order as in the source code. First paragraph is used for short description and is also available via `firstParagraph`. Each object is a `GBCommentParagraph` instance and should be registered through `registerParagraph:` method.
@see firstParagraph
+ @see descriptionParagraphs
@see registerParagraph:
@see parameters
@see exceptions
@@ -99,6 +102,31 @@
@property (readonly) NSArray *paragraphs;
///---------------------------------------------------------------------------------------
+/// @name Description paragraphs handling
+///---------------------------------------------------------------------------------------
+
+/** Registers the `GBCommentParagraph` and adds it to the end of `descriptionParagraphs` array.
+
+ If `descriptionParagraphs` is `nil`, a new array is created before adding the given object to it.
+
+ @param paragraph Paragraph to register.
+ @exception NSException Thrown if the given paragraph is `nil`.
+ @see descriptionParagraphs
+ @see registerParagraph:
+ */
+- (void)registerDescriptionParagraph:(GBCommentParagraph *)paragraph;
+
+/** `NSArray` containing all paragraphs that should be used for object description.
+
+ The paragraphs are in the same order as in the source code. Each object is a `GBCommentParagraph` instance and should be registered through `registerDescriptionParagraph:` method. This array may be the same as `paragraphs` or it may be different, depending the application settings. It's up to client code to provide the description paragraphs!
+
+ @see paragraphs
+ @see hasDescriptionParagraphs
+ @see registerDescriptionParagraph:
+ */
+@property (readonly) NSArray *descriptionParagraphs;
+
+///---------------------------------------------------------------------------------------
/// @name Method arguments handling
///---------------------------------------------------------------------------------------
@@ -218,21 +246,21 @@
/** Indicates whether the comment has at least one paragraph or not.
- This is used mainly to simplify template output generators. Programmatically this method is equal to testing whether `paragraph` count is greater than 0, like this: `[object.paragraphs count] > 0`.
+ This is used mainly to simplify template output generators. Programmatically this method is equal to testing whether `paragraphs` count is greater than 0, like this: `[object.paragraphs count] > 0`.
- @see hasMultipleParagraphs
+ @see hasDescriptionParagraphs
@see paragraphs
*/
@property (readonly) BOOL hasParagraphs;