Permalink
Browse files

Implemented possibility of injecting descriptions to main index file. C…

…loses #74.

Using `--index-desc` switch, you can pass the path to the file containing description that'll be injected in the auto generated index.html. The file can be formatted using the same rules as any other static document. The difference is it's not possible to link to it from other objects or documents (each generated object html already contains the link to main index and hierarchy). But it's possible to link any class or document from within the index description; the same logic is used for that as for any other source code comment or static document.

Online documentation will follow briefly... For now give it a try and let me know if there's anything else missing or something not working as expected.
  • Loading branch information...
1 parent 90e3553 commit 7d185695da06ded93460f5a36fe2d598a8573dbd @tomaz committed Mar 3, 2011
@@ -21,6 +21,7 @@
static NSString *kGBArgTemplatesPath = @"templates";
static NSString *kGBArgDocSetInstallPath = @"docset-install-path";
static NSString *kGBArgDocSetUtilPath = @"docsetutil-path";
+static NSString *kGBArgIndexDescPath = @"index-desc";
static NSString *kGBArgIncludePath = @"include";
static NSString *kGBArgIgnorePath = @"ignore";
@@ -177,6 +178,7 @@ - (int)application:(DDCliApplication *)app runWithArguments:(NSArray *)arguments
GBParser *parser = [GBParser parserWithSettingsProvider:self.settings];
[parser parseObjectsFromPaths:inputs toStore:store];
[parser parseDocumentsFromPaths:[self.settings.includePaths allObjects] toStore:store];
+ [parser parseCustomDocumentFromPath:self.settings.indexDescriptionPath outputSubpath:@"" key:kGBCustomDocumentIndexDescKey toStore:store];
GBAbsoluteTime parseTime = GetCurrentTime();
NSUInteger timeForParsing = SubtractTime(parseTime, startTime) * 1000.0;
GBLogInfo(@"Finished parsing in %ldms.\n", timeForParsing);
@@ -215,6 +217,7 @@ - (void)application:(DDCliApplication *)app willParseOptions:(DDGetoptLongParser
{ kGBArgTemplatesPath, 't', DDGetoptRequiredArgument },
{ kGBArgIgnorePath, 'i', DDGetoptRequiredArgument },
{ kGBArgIncludePath, 's', DDGetoptRequiredArgument },
+ { kGBArgIndexDescPath, 0, DDGetoptRequiredArgument },
{ kGBArgDocSetInstallPath, 0, DDGetoptRequiredArgument },
{ kGBArgDocSetUtilPath, 0, DDGetoptRequiredArgument },
@@ -374,6 +377,24 @@ - (void)validateSettingsAndArguments:(NSArray *)arguments {
ddprintf(@"WARN: --%@ argument or global setting not given, but creating DocSet is enabled, will use '%@'!\n", kGBArgCompanyIdentifier, self.settings.companyIdentifier);
}
}
+
+ // If any of the include paths isn't valid, warn.
+ [self.settings.includePaths enumerateObjectsUsingBlock:^(NSString *userPath, BOOL *stop) {
+ NSString *path = [userPath stringByStandardizingPath];
+ if (![self.fileManager fileExistsAtPath:path]) {
+ ddprintf(@"WARNL --%@ path '%@' doesn't exist, ignoring!\n", kGBArgIncludePath, userPath);
+ }
+ }];
+
+ // If index description path is given but doesn't point to an existing file, warn.
+ if ([self.settings.indexDescriptionPath length] > 0) {
+ BOOL isDir;
+ NSString *path = [self.settings.indexDescriptionPath stringByStandardizingPath];
+ if (![self.fileManager fileExistsAtPath:path isDirectory:&isDir])
+ ddprintf(@"WARN: --%@ path '%@' doesn't exist, ignoring!\n", kGBArgIndexDescPath, self.settings.indexDescriptionPath);
+ else if (isDir)
+ ddprintf(@"WARN: --%@ path '%@' is a directory, file is required, ignoring!\n", kGBArgIndexDescPath, self.settings.indexDescriptionPath);
+ }
}
- (BOOL)validateTemplatesPath:(NSString *)path error:(NSError **)error {
@@ -569,6 +590,7 @@ - (void)setOutput:(NSString *)path { self.settings.outputPath = [self standardiz
- (void)setDocsetInstallPath:(NSString *)path { self.settings.docsetInstallPath = [self standardizeCurrentDirectoryForPath:path]; }
- (void)setDocsetutilPath:(NSString *)path { self.settings.docsetUtilPath = [self standardizeCurrentDirectoryForPath:path]; }
- (void)setInclude:(NSString *)path { [self.settings.includePaths addObject:[self standardizeCurrentDirectoryForPath:path]]; }
+- (void)setIndexDesc:(NSString *)path { self.settings.indexDescriptionPath = [self standardizeCurrentDirectoryForPath:path]; }
- (void)setTemplates:(NSString *)path { self.settings.templatesPath = [self standardizeCurrentDirectoryForPath:path]; }
- (void)setIgnore:(NSString *)path {
if ([path hasPrefix:@"*"]) path = [path substringFromIndex:1];
@@ -714,6 +736,7 @@ - (void)printSettingsAndArguments:(NSArray *)arguments {
ddprintf(@"--%@ = %@\n", kGBArgTemplatesPath, self.settings.templatesPath);
ddprintf(@"--%@ = %@\n", kGBArgOutputPath, self.settings.outputPath);
+ ddprintf(@"--%@ = %@\n", kGBArgIndexDescPath, self.settings.indexDescriptionPath);
for (NSString *path in self.settings.includePaths) ddprintf(@"--%@ = %@\n", kGBArgIncludePath, path);
for (NSString *path in self.settings.ignoredPaths) ddprintf(@"--%@ = %@\n", kGBArgIgnorePath, path);
ddprintf(@"--%@ = %@\n", kGBArgDocSetInstallPath, self.settings.docsetInstallPath);
@@ -789,6 +812,7 @@ - (void)printHelp {
PRINT_USAGE(@" ", kGBArgDocSetInstallPath, @"<path>", @"DocSet installation path");
PRINT_USAGE(@"-s,", kGBArgIncludePath, @"<path>", @"Include static doc(s) at path");
PRINT_USAGE(@"-i,", kGBArgIgnorePath, @"<path>", @"Ignore given path");
+ PRINT_USAGE(@" ", kGBArgIndexDescPath, @"<path>", @"File including main index description");
ddprintf(@"\n");
ddprintf(@"PROJECT INFO\n");
PRINT_USAGE(@"-p,", kGBArgProjectName, @"<string>", @"Project name");
@@ -11,6 +11,10 @@
@class GBModelBase;
+extern id kGBCustomDocumentIndexDescKey;
+
+#pragma mark -
+
/** 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.
@@ -141,9 +145,19 @@
@warning *Note:* All include paths are copied over to destination defined with `outputPath`, inside `docs` directory. If a path represents a directory, it's copied into a subdirectory of `docs` using the last path component name as the subdirectory name. For example: contents of `some/path/to/dir` would be copied to `docs/dir` within `outputPath` and `another/path` would be copied to `docs/path`. In case the path represents a file, it's simply copied inside `docs` directory at `outputPath`.
@warning *Important:* Make sure no duplicate directories or files are added to the list - appledoc will fail in such case! Also make sure to not add subpaths of an already added path - this will also fail while copying files!
+
+ @see indexDescriptionPath
*/
@property (retain) NSMutableSet *includePaths;
+/** The path to the source file used for injection into autogenerated main index html.
+
+ If this is valid value, pointing to an existing file, it's used to inject the contents of the file into autogenerated main index html. The source file is preprocessed using the same rules as all other static documents.
+
+ @see includePaths
+ */
+@property (copy) NSString *indexDescriptionPath;
+
/** The list of all full or partial paths to be ignored.
It's recommended to check if a path string ends with any of the given paths before processing it. This should catch directory and file names properly as directories are processed first.
@@ -24,6 +24,8 @@
NSString *kGBTemplatePlaceholderYear = @"%YEAR";
NSString *kGBTemplatePlaceholderUpdateDate = @"%UPDATEDATE";
+NSString *kGBCustomDocumentIndexDescKey = @"index-description";
+
#pragma mark -
@interface GBApplicationSettingsProvider ()
@@ -65,6 +67,7 @@ - (id)init {
self.templatesPath = nil;
self.docsetInstallPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Developer/Shared/Documentation/DocSets"];
self.docsetUtilPath = @"/Developer/usr/bin/docsetutil";
+ self.indexDescriptionPath = nil;
self.includePaths = [NSMutableSet set];
self.ignoredPaths = [NSMutableSet set];
@@ -405,21 +408,27 @@ - (NSString *)outputPathForObject:(id)object withExtension:(NSString *)extension
}
else if ([object isKindOfClass:[GBDocumentData class]]) {
GBDocumentData *document = object;
-
- // Get output filename (removing template suffix) and document subpath without filename. Note that we need to remove extension as we'll add html by default!
- NSString *subpath = [document.subpathOfDocument stringByDeletingLastPathComponent];
- NSString *filename = [self outputFilenameForTemplatePath:document.pathOfDocument];
- filename = [filename stringByDeletingPathExtension];
- // If the document is included as part of a directory structure, we should use subdir, otherwise just leave the filename.
- if (![document.basePathOfDocument isEqualToString:document.pathOfDocument]) {
- NSString *includePath = [document.basePathOfDocument lastPathComponent];
- subpath = [includePath stringByAppendingPathComponent:subpath];
+ // If this is custom document, just use it's relative path, otherwise take into account the registered path.
+ if (document.isCustomDocument) {
+ basePath = document.basePathOfDocument;
+ name = document.nameOfDocument;
+ } else {
+ // Get output filename (removing template suffix) and document subpath without filename. Note that we need to remove extension as we'll add html by default!
+ NSString *subpath = [document.subpathOfDocument stringByDeletingLastPathComponent];
+ NSString *filename = [self outputFilenameForTemplatePath:document.pathOfDocument];
+ filename = [filename stringByDeletingPathExtension];
+
+ // If the document is included as part of a directory structure, we should use subdir, otherwise just leave the filename.
+ if (![document.basePathOfDocument isEqualToString:document.pathOfDocument]) {
+ NSString *includePath = [document.basePathOfDocument lastPathComponent];
+ subpath = [includePath stringByAppendingPathComponent:subpath];
+ }
+
+ // Prepare relative path from output path to the document now.
+ basePath = [self.htmlStaticDocumentsSubpath stringByAppendingPathComponent:subpath];
+ name = filename;
}
-
- // Prepare relative path from output path to the document now.
- basePath = [self.htmlStaticDocumentsSubpath stringByAppendingPathComponent:subpath];
- name = filename;
}
if (basePath == nil || name == nil) return nil;
@@ -437,6 +446,8 @@ - (NSString *)htmlRelativePathToIndexFromObject:(id)object {
NSMutableString *result = [NSMutableString stringWithCapacity:[subpath length]];
for (NSUInteger i=0; i<[components count]; i++) [result appendString:@"../"];
return result;
+ } else {
+ return @"";
}
}
return @"../";
@@ -513,6 +524,7 @@ - (NSString *)versionIdentifier {
@synthesize docsetUtilPath;
@synthesize templatesPath;
@synthesize includePaths;
+@synthesize indexDescriptionPath;
@synthesize ignoredPaths;
@synthesize docsetBundleIdentifier;
@@ -19,6 +19,7 @@ @interface GBHTMLTemplateVariablesProvider ()
- (NSString *)hrefForObject:(id)object fromObject:(id)source;
- (NSDictionary *)arrayDescriptorForArray:(NSArray *)array;
+- (void)addCustomDocumentWithKey:(id)key toDictionary:(NSMutableDictionary *)dict key:(id)dictKey;
- (void)addFooterVarsToDictionary:(NSMutableDictionary *)dict;
@property (retain) GBStore *store;
@property (retain) GBApplicationSettingsProvider *settings;
@@ -156,6 +157,7 @@ - (NSDictionary *)variablesForIndexWithStore:(id)store {
[result setObject:[self protocolsForIndex] forKey:@"protocols"];
[result setObject:[self categoriesForIndex] forKey:@"categories"];
[result setObject:self.settings.stringTemplates forKey:@"strings"];
+ [self addCustomDocumentWithKey:kGBCustomDocumentIndexDescKey toDictionary:result key:@"indexDescription"];
[self registerObjectsUsageForIndexInDictionary:result];
return result;
}
@@ -199,6 +201,13 @@ - (NSDictionary *)arrayDescriptorForArray:(NSArray *)array {
#pragma mark Common values
+- (void)addCustomDocumentWithKey:(id)key toDictionary:(NSMutableDictionary *)dict key:(id)dictKey {
+ // Adds custom document with the given key to the given dictionary using the given dictionary key. If custom document isn't found, nothing happens.
+ GBDocumentData *document = [self.store customDocumentWithKey:key];
+ if (!document) return;
+ [dict setObject:document forKey:dictKey];
+}
+
- (void)addFooterVarsToDictionary:(NSMutableDictionary *)dict {
[dict setObject:self.settings.projectCompany forKey:@"copyrightHolder"];
[dict setObject:[self.settings stringByReplacingOccurencesOfPlaceholdersInString:kGBTemplatePlaceholderYear] forKey:@"copyrightDate"];
View
@@ -98,4 +98,10 @@
*/
@property (readonly) NSString *subpathOfDocument;
+/** Specifies whether this is custom document or not.
+
+ This is used when creating cross references; if the value is `YES`, `basePathOfDocument` is considered as the subpath from the root output path.
+ */
+@property (assign) BOOL isCustomDocument;
+
@end
View
@@ -64,6 +64,7 @@ - (NSString *)subpathOfDocument {
return result;
}
+@synthesize isCustomDocument;
@synthesize nameOfDocument;
@synthesize pathOfDocument;
@synthesize basePathOfDocument;
View
@@ -27,6 +27,8 @@
NSMutableDictionary *_protocolsByName;
NSMutableSet *_documents;
NSMutableDictionary *_documentsByName;
+ NSMutableSet *_customDocuments;
+ NSMutableDictionary *_customDocumentsByKey;
}
///---------------------------------------------------------------------------------------
@@ -94,6 +96,17 @@
*/
- (void)registerDocument:(GBDocumentData *)document;
+/** Registers the given custom document to the store data.
+
+ If store doesn't yet have the given document registered, the object is added to custom documents list by it's key. If the list already contains the object, exception is raised.
+
+ @param document The document to register.
+ @param key The key to register document with.
+ @exception NSException Thrown if the given document is already registered.
+ @see customDocumentWithKey:
+ */
+- (void)registerCustomDocument:(GBDocumentData *)document withKey:(id)key;
+
/** Unregisters the given class, category or protocol.
If the object is not part of the store, nothing happens.
@@ -155,6 +168,16 @@
*/
- (GBDocumentData *)documentWithName:(NSString *)path;
+/** Returns the custom document that matches the given key.
+
+ If no registered custom document matches the given key, `nil` is returned.
+
+ @param key The key of the document.
+ @return Returns document instance or `nil` if no match is found.
+ @see customDocuments
+ */
+- (GBDocumentData *)customDocumentWithKey:(id)key;
+
/** The list of all registered classes as instances of `GBClassData`.
@see classWithName:
@@ -178,10 +201,18 @@
/** The list of all registered documents as instances of `GBDocumentData`.
+ @see documentWithName:
@see registerDocument:
*/
@property (readonly) NSSet *documents;
+/** The list of all registered custom documents as instances of `GBDocumentData`.
+
+ @see customDocumentWithKey:
+ @see registerCustomDocument:withKey:
+ */
+@property (readonly) NSSet *customDocuments;
+
///---------------------------------------------------------------------------------------
/// @name Helper methods
///---------------------------------------------------------------------------------------
View
@@ -24,6 +24,8 @@ - (id)init {
_protocolsByName = [[NSMutableDictionary alloc] init];
_documents = [[NSMutableSet alloc] init];
_documentsByName = [[NSMutableDictionary alloc] init];
+ _customDocuments = [[NSMutableSet alloc] init];
+ _customDocumentsByKey = [[NSMutableDictionary alloc] init];
}
return self;
}
@@ -110,6 +112,13 @@ - (void)registerDocument:(GBDocumentData *)document {
[_documentsByName setObject:document forKey:[name stringByReplacingOccurrencesOfString:@"-template" withString:@""]];
}
+- (void)registerCustomDocument:(GBDocumentData *)document withKey:(id)key {
+ NSParameterAssert(document != nil);
+ GBLogDebug(@"Registering custom document %@...", document);
+ [_customDocuments addObject:document];
+ [_customDocumentsByKey setObject:document forKey:key];
+}
+
- (void)unregisterTopLevelObject:(id)object {
if ([_classes containsObject:object]) {
[_classes removeObject:object];
@@ -146,9 +155,14 @@ - (GBDocumentData *)documentWithName:(NSString *)path {
return [_documentsByName objectForKey:path];
}
+- (GBDocumentData *)customDocumentWithKey:(id)key {
+ return [_customDocumentsByKey objectForKey:key];
+}
+
@synthesize classes = _classes;
@synthesize categories = _categories;
@synthesize protocols = _protocols;
@synthesize documents = _documents;
+@synthesize customDocuments = _customDocuments;
@end
View
@@ -52,6 +52,7 @@
@param store The store to add objects to.
@exception NSException Thrown if a serious problem is detected which prevents us from parsing.
@see parseDocumentsFromPaths:toStore:
+ @see parseCustomDocumentFromPath:toStore:
*/
- (void)parseObjectsFromPaths:(NSArray *)paths toStore:(id)store;
@@ -65,7 +66,21 @@
@param store The store to add objects to.
@exception NSException Thrown if a serious problem is detected which prevents us from parsing.
@see parseObjectsFromPaths:toStore:
+ @see parseCustomDocumentFromPath:outputSubpath:key:toStore:
*/
- (void)parseDocumentsFromPaths:(NSArray *)paths toStore:(id)store;
+/** Scans the given file and parses it as custom static document files into in-memory objects.
+
+ Custom static documents are not standalone documents, but rather fractions of documents used for injection into other parts. For example: main index file documentation. This is the main method for these documents parsing. It is intended to be invoked from the top level application code. Is accepts a path to a filename and parses it the same way as normal static documents. Parsed data is registered to the given `GBStore`, each document using it's document filename without extension as the key. If the document is empty, a warning is issued, and the document is not registered.
+
+ @param path The string containing filename and path to the document.
+ @param outputPath The subpath relative to output path the object will be saved to.
+ @param store The store to add objects to.
+ @exception NSException Thrown if a serious problem is detected which prevents us from parsing.
+ @see parseObjectsFromPaths:toStore:
+ @see parseDocumentsFromPath:toStore:
+ */
+- (void)parseCustomDocumentFromPath:(NSString *)path outputSubpath:(NSString *)subpath key:(id)key toStore:(id)store;
+
@end
View
@@ -107,6 +107,29 @@ - (void)parseDocumentsFromPaths:(NSArray *)paths toStore:(id)store {
GBLogVerbose(@"Parsed %lu static document files.", self.numberOfParsedDocuments);
}
+- (void)parseCustomDocumentFromPath:(NSString *)path outputSubpath:(NSString *)subpath key:(id)key toStore:(id)store {
+ NSParameterAssert(key != nil);
+ NSParameterAssert(store != nil);
+ self.store = store;
+ GBLogVerbose(@"Parsing custom document from '%@'...", path);
+
+ NSError *error = nil;
+ NSString *contents = [NSString stringWithContentsOfFile:[path stringByStandardizingPath] encoding:NSUTF8StringEncoding error:&error];
+ if (error) {
+ GBLogNSError(error, @"Failed reading contents of custom document '%@'...", path);
+ return;
+ }
+ if ([contents length] == 0) {
+ GBLogWarn(@"Empty custom document found at '%@'!", path);
+ return;
+ }
+
+ GBDocumentData *document = [GBDocumentData documentDataWithContents:contents path:path];
+ document.isCustomDocument = YES;
+ document.basePathOfDocument = subpath;
+ [self.store registerCustomDocument:document withKey:key];
+}
+
#pragma mark Parsing helpers
- (void)parsePath:(NSString *)input usingBlock:(void (^)(NSString *path))block {
Oops, something went wrong.

0 comments on commit 7d18569

Please sign in to comment.