Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'development'

  • Loading branch information...
commit 33594ce4571af5063fecae8e582933564c7483ee 2 parents e9448e7 + 1b9a0bd
@tomaz authored
Showing with 573 additions and 291 deletions.
  1. +1 −1  AppledocTests-Info.plist
  2. +27 −11 Application/GBAppledocApplication.m
  3. +31 −2 Application/GBApplicationSettingsProvider.h
  4. +50 −20 Application/GBApplicationSettingsProvider.m
  5. +2 −2 Application/GBApplicationStringsProvider.m
  6. +84 −0 Developer Notes.markdown
  7. +15 −0 Generating/GBDocSetInstallGenerator.h
  8. +68 −0 Generating/GBDocSetInstallGenerator.m
  9. +2 −104 Generating/GBDocSetOutputGenerator.m
  10. +15 −0 Generating/GBDocSetPublishGenerator.h
  11. +83 −0 Generating/GBDocSetPublishGenerator.m
  12. +6 −0 Generating/GBGenerator.m
  13. +2 −2 Generating/GBHTMLTemplateVariablesProvider.m
  14. +12 −0 Generating/GBOutputGenerator.h
  15. +5 −0 Generating/GBOutputGenerator.m
  16. +6 −6 Parsing/GBTokenizer.m
  17. +11 −6 Processing/GBCommentsProcessor.m
  18. +26 −6 Readme.markdown
  19. +0 −113 Release Notes.markdown
  20. +2 −2 Templates/html/hierarchy-template.html
  21. +2 −2 Templates/html/index-template.html
  22. +2 −2 Templates/html/object-template.html
  23. +18 −0 Testing/GBApplicationTesting.m
  24. +69 −8 Testing/GBCommentsProcessor-ExamplesTesting.m
  25. +16 −2 Testing/GBTokenizerTesting.m
  26. +18 −2 appledoc.xcodeproj/project.pbxproj
View
2  AppledocTests-Info.plist
@@ -17,6 +17,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
- <string>514</string>
+ <string>530</string>
</dict>
</plist>
View
38 Application/GBAppledocApplication.m
@@ -45,6 +45,8 @@
static NSString *kGBArgWarnOnMissingCompanyIdentifier = @"warn-missing-company-id";
static NSString *kGBArgWarnOnUndocumentedObject = @"warn-undocumented-object";
static NSString *kGBArgWarnOnUndocumentedMember = @"warn-undocumented-member";
+static NSString *kGBArgWarnOnEmptyDescription = @"warn-empty-description";
+static NSString *kGBArgWarnOnUnknownDirective = @"warn-unknown-directive";
static NSString *kGBArgWarnOnInvalidCrossReference = @"warn-invalid-crossref";
static NSString *kGBArgWarnOnMissingMethodArgument = @"warn-missing-arg";
@@ -245,12 +247,16 @@ - (void)application:(DDCliApplication *)app willParseOptions:(DDGetoptLongParser
{ kGBArgWarnOnMissingCompanyIdentifier, 0, DDGetoptNoArgument },
{ kGBArgWarnOnUndocumentedObject, 0, DDGetoptNoArgument },
{ kGBArgWarnOnUndocumentedMember, 0, DDGetoptNoArgument },
+ { kGBArgWarnOnEmptyDescription, 0, DDGetoptNoArgument },
+ { kGBArgWarnOnUnknownDirective, 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(kGBArgWarnOnEmptyDescription), 0, DDGetoptNoArgument },
+ { GBNoArg(kGBArgWarnOnUnknownDirective), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgWarnOnInvalidCrossReference), 0, DDGetoptNoArgument },
{ GBNoArg(kGBArgWarnOnMissingMethodArgument), 0, DDGetoptNoArgument },
@@ -475,12 +481,16 @@ - (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)setWarnEmptyDescription:(BOOL)value { self.settings.warnOnEmptyDescription = value; }
+- (void)setWarnUnknownDirective:(BOOL)value { self.settings.warnOnUnknownDirective = 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)setNoWarnEmptyDescription:(BOOL)value { self.settings.warnOnEmptyDescription = !value; }
+- (void)setNoWarnUnknownDirective:(BOOL)value { self.settings.warnOnUnknownDirective = !value; }
- (void)setNoWarnInvalidCrossref:(BOOL)value { self.settings.warnOnInvalidCrossReference = !value; }
- (void)setNoWarnMissingArg:(BOOL)value { self.settings.warnOnMissingMethodArgument = !value; }
@@ -578,6 +588,10 @@ - (void)printSettingsAndArguments:(NSArray *)arguments {
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", kGBArgWarnOnEmptyDescription, PRINT_BOOL(self.settings.warnOnEmptyDescription));
+ ddprintf(@"--%@ = %@\n", kGBArgWarnOnUnknownDirective, PRINT_BOOL(self.settings.warnOnUnknownDirective));
+ ddprintf(@"--%@ = %@\n", kGBArgWarnOnInvalidCrossReference, PRINT_BOOL(self.settings.warnOnInvalidCrossReference));
+ ddprintf(@"--%@ = %@\n", kGBArgWarnOnMissingMethodArgument, PRINT_BOOL(self.settings.warnOnMissingMethodArgument));
ddprintf(@"\n");
ddprintf(@"--%@ = %@\n", kGBArgLogFormat, self.logformat);
@@ -631,6 +645,8 @@ - (void)printHelp {
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(@" ", kGBArgWarnOnEmptyDescription, @"", @"[b] Warn on empty description block");
+ PRINT_USAGE(@" ", kGBArgWarnOnUnknownDirective, @"", @"[b] Warn on unknown directive or format");
PRINT_USAGE(@" ", kGBArgWarnOnInvalidCrossReference, @"", @"[b] Warn on invalid cross reference");
PRINT_USAGE(@" ", kGBArgWarnOnMissingMethodArgument, @"", @"[b] Warn on missing method argument documentation");
ddprintf(@"\n");
@@ -663,17 +679,17 @@ - (void)printHelp {
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(@"- %%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(@"- %@ replaced with --project-name\n", kGBTemplatePlaceholderProject);
+ ddprintf(@"- %@ replaced with normalized --project-name\n", kGBTemplatePlaceholderProjectID);
+ ddprintf(@"- %@ replaced with --project-version\n", kGBTemplatePlaceholderVersion);
+ ddprintf(@"- %@ replaced with normalized --project-version\n", kGBTemplatePlaceholderVersionID);
+ ddprintf(@"- %@ replaced with --project-company\n", kGBTemplatePlaceholderCompany);
+ ddprintf(@"- %@ replaced with --company-id\n", kGBTemplatePlaceholderCompanyID);
+ ddprintf(@"- %@ replaced with current year (format yyyy)\n", kGBTemplatePlaceholderYear);
+ ddprintf(@"- %@ replaced with current date (format yyyy-MM-dd)\n", kGBTemplatePlaceholderUpdateDate);
+ ddprintf(@"- %@ replaced with --docset-bundle-filename\n", kGBTemplatePlaceholderDocSetBundleFilename);
+ ddprintf(@"- %@ replaced with --docset-atom-filename\n", kGBTemplatePlaceholderDocSetAtomFilename);
+ ddprintf(@"- %@ replaced with --docset-package-filename\n", kGBTemplatePlaceholderDocSetPackageFilename);
ddprintf(@"\n");
ddprintf(@"==================================================================\n");
ddprintf(@"Find more help and tips online:\n");
View
33 Application/GBApplicationSettingsProvider.h
@@ -24,7 +24,7 @@
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!).
+ 3. Add unit test in `GBAppledocApplicationTesting.m` that validates the switch is properly mapped to setting property (note that boolean switches 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.
@@ -294,12 +294,20 @@
*/
@property (assign) BOOL warnOnUndocumentedObject;
-/** Indicates whether appldoc will warn if it encounters an undocumented method or property.
+/** Indicates whether appledoc will warn if it encounters an undocumented method or property.
@see warnOnUndocumentedObject
*/
@property (assign) BOOL warnOnUndocumentedMember;
+/** Indicates whether appledoc will warn if it encounters an empty description (@bug, @warning, example section etc.).
+ */
+@property (assign) BOOL warnOnEmptyDescription;
+
+/** Indicates whether appledoc will warn if it encounters unknown directive or styling element.
+ */
+@property (assign) BOOL warnOnUnknownDirective;
+
/** Indicates whether invalid cross reference should result in warning or not. */
@property (assign) BOOL warnOnInvalidCrossReference;
@@ -310,6 +318,13 @@
/// @name Application-wide HTML helpers
///---------------------------------------------------------------------------------------
+/** Returns a new string by escaping the given HTML.
+
+ @param string HTML string to escape.
+ @return Returns escaped HTML string.
+ */
+- (NSString *)stringByEscapingHTML:(NSString *)string;
+
/** Returns HTML reference name for the given object.
This should only be used for creating anchors that need to be referenced from other parts of the same HTML file. The method works for top-level objects as well as their members.
@@ -408,3 +423,17 @@
@property (retain) GBApplicationStringsProvider *stringTemplates;
@end
+
+#pragma -
+
+extern NSString *kGBTemplatePlaceholderCompanyID;
+extern NSString *kGBTemplatePlaceholderProjectID;
+extern NSString *kGBTemplatePlaceholderVersionID;
+extern NSString *kGBTemplatePlaceholderProject;
+extern NSString *kGBTemplatePlaceholderCompany;
+extern NSString *kGBTemplatePlaceholderVersion;
+extern NSString *kGBTemplatePlaceholderDocSetBundleFilename;
+extern NSString *kGBTemplatePlaceholderDocSetAtomFilename;
+extern NSString *kGBTemplatePlaceholderDocSetPackageFilename;
+extern NSString *kGBTemplatePlaceholderYear;
+extern NSString *kGBTemplatePlaceholderUpdateDate;
View
70 Application/GBApplicationSettingsProvider.m
@@ -11,6 +11,20 @@
#import "GBDataObjects.h"
#import "GBApplicationSettingsProvider.h"
+NSString *kGBTemplatePlaceholderCompanyID = @"%COMPANYID";
+NSString *kGBTemplatePlaceholderProjectID = @"%PROJECTID";
+NSString *kGBTemplatePlaceholderVersionID = @"%VERSIONID";
+NSString *kGBTemplatePlaceholderProject = @"%PROJECT";
+NSString *kGBTemplatePlaceholderCompany = @"%COMPANY";
+NSString *kGBTemplatePlaceholderVersion = @"%VERSION";
+NSString *kGBTemplatePlaceholderDocSetBundleFilename = @"%DOCSETBUNDLEFILENAME";
+NSString *kGBTemplatePlaceholderDocSetAtomFilename = @"%DOCSETATOMFILENAME";
+NSString *kGBTemplatePlaceholderDocSetPackageFilename = @"%DOCSETPACKAGEFILENAME";
+NSString *kGBTemplatePlaceholderYear = @"%YEAR";
+NSString *kGBTemplatePlaceholderUpdateDate = @"%UPDATEDATE";
+
+#pragma mark -
+
@interface GBApplicationSettingsProvider ()
+ (NSSet *)nonCopyableProperties;
@@ -70,11 +84,13 @@ - (id)init {
self.warnOnMissingCompanyIdentifier = YES;
self.warnOnUndocumentedObject = YES;
self.warnOnUndocumentedMember = YES;
+ self.warnOnEmptyDescription = YES;
+ self.warnOnUnknownDirective = YES;
self.warnOnInvalidCrossReference = YES;
self.warnOnMissingMethodArgument = YES;
- self.docsetBundleIdentifier = @"%COMPANYID.%PROJECTID";
- self.docsetBundleName = @"%PROJECT Documentation";
+ self.docsetBundleIdentifier = [NSString stringWithFormat:@"%@.%@", kGBTemplatePlaceholderCompanyID, kGBTemplatePlaceholderProjectID];
+ self.docsetBundleName = [NSString stringWithFormat:@"%@ Documentation", kGBTemplatePlaceholderProject];
self.docsetCertificateIssuer = @"";
self.docsetCertificateSigner = @"";
self.docsetDescription = @"";
@@ -84,13 +100,13 @@ - (id)init {
self.docsetPackageURL = @"";
self.docsetMinimumXcodeVersion = @"3.0";
self.docsetPlatformFamily = @"";
- self.docsetPublisherIdentifier = @"%COMPANYID.documentation";
- self.docsetPublisherName = @"%COMPANY";
- self.docsetCopyrightMessage = @"Copyright © %YEAR %COMPANY. All rights reserved.";
+ self.docsetPublisherIdentifier = [NSString stringWithFormat:@"%@.documentation", kGBTemplatePlaceholderCompanyID];
+ self.docsetPublisherName = [NSString stringWithFormat:@"%@", kGBTemplatePlaceholderCompany];
+ self.docsetCopyrightMessage = [NSString stringWithFormat:@"Copyright © %@ %@. All rights reserved.", kGBTemplatePlaceholderYear, kGBTemplatePlaceholderCompany];
- self.docsetBundleFilename = @"%COMPANYID.%PROJECTID.docset";
- self.docsetAtomFilename = @"%COMPANYID.%PROJECTID.atom";
- self.docsetPackageFilename = @"%COMPANYID.%PROJECTID-%VERSIONID.xar";
+ self.docsetBundleFilename = [NSString stringWithFormat:@"%@.%@.docset", kGBTemplatePlaceholderCompanyID, kGBTemplatePlaceholderProjectID];
+ self.docsetAtomFilename = [NSString stringWithFormat:@"%@.%@.atom", kGBTemplatePlaceholderCompanyID, kGBTemplatePlaceholderProjectID];
+ self.docsetPackageFilename = [NSString stringWithFormat:@"%@.%@-%@.xar", kGBTemplatePlaceholderCompanyID, kGBTemplatePlaceholderProjectID, kGBTemplatePlaceholderVersionID];
self.commentComponents = [GBCommentComponentsProvider provider];
self.stringTemplates = [GBApplicationStringsProvider provider];
@@ -122,7 +138,19 @@ - (void)replaceAllOccurencesOfPlaceholderStringsInSettingsValues {
self.docsetCopyrightMessage = [self stringByReplacingOccurencesOfPlaceholdersInString:self.docsetCopyrightMessage];
}
-#pragma mark HTML references handling
+#pragma mark Common HTML handling
+
+- (NSString *)stringByEscapingHTML:(NSString *)string {
+ // Copied directly from GRMustache's GRMustacheVariableElement.m...
+ NSMutableString *result = [NSMutableString stringWithCapacity:5 + ceilf(string.length * 1.1)];
+ [result appendString:string];
+ [result replaceOccurrencesOfString:@"&" withString:@"&amp;" options:NSLiteralSearch range:NSMakeRange(0, result.length)];
+ [result replaceOccurrencesOfString:@"<" withString:@"&lt;" options:NSLiteralSearch range:NSMakeRange(0, result.length)];
+ [result replaceOccurrencesOfString:@">" withString:@"&gt;" options:NSLiteralSearch range:NSMakeRange(0, result.length)];
+ [result replaceOccurrencesOfString:@"\"" withString:@"&quot;" options:NSLiteralSearch range:NSMakeRange(0, result.length)];
+ [result replaceOccurrencesOfString:@"'" withString:@"&apos;" options:NSLiteralSearch range:NSMakeRange(0, result.length)];
+ return result;
+}
- (NSString *)htmlReferenceNameForObject:(GBModelBase *)object {
NSParameterAssert(object != nil);
@@ -266,17 +294,17 @@ - (BOOL)isTopLevelStoreObject:(id)object {
}
- (NSString *)stringByReplacingOccurencesOfPlaceholdersInString:(NSString *)string {
- 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]]];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderCompanyID withString:self.companyIdentifier];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderProjectID withString:self.projectIdentifier];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderVersionID withString:self.versionIdentifier];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderProject withString:self.projectName];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderCompany withString:self.projectCompany];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderVersion withString:self.projectVersion];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderDocSetBundleFilename withString:self.docsetBundleFilename];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderDocSetAtomFilename withString:self.docsetAtomFilename];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderDocSetPackageFilename withString:self.docsetPackageFilename];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderYear withString:[self yearStringFromDate:[NSDate date]]];
+ string = [string stringByReplacingOccurrencesOfString:kGBTemplatePlaceholderUpdateDate withString:[self yearToDayStringFromDate:[NSDate date]]];
return string;
}
@@ -367,6 +395,8 @@ - (NSString *)versionIdentifier {
@synthesize warnOnMissingCompanyIdentifier;
@synthesize warnOnUndocumentedObject;
@synthesize warnOnUndocumentedMember;
+@synthesize warnOnEmptyDescription;
+@synthesize warnOnUnknownDirective;
@synthesize warnOnInvalidCrossReference;
@synthesize warnOnMissingMethodArgument;
View
4 Application/GBApplicationStringsProvider.m
@@ -124,8 +124,8 @@ - (NSDictionary *)appledocData {
if (!result) {
result = [[NSMutableDictionary alloc] init];
[result setObject:@"appledoc" forKey:@"tool"];
- [result setObject:@"2.0" forKey:@"version"];
- [result setObject:@"514" forKey:@"build"];
+ [result setObject:@"2.0.1" forKey:@"version"];
+ [result setObject:@"530" forKey:@"build"];
[result setObject:@"http://appledoc.gentlebytes.com" forKey:@"homepage"];
}
return result;
View
84 Developer Notes.markdown
@@ -0,0 +1,84 @@
+Release Checklist
+=================
+
+All low level key components are covered with unit tests, however some higher level components aren't so make sure you check all following tests before releasing a version.
+
+- Compile as release to fix missing @synthesize and similar.
+- Make sure all unit tests pass.
+- Validate all input paths are parsed.
+- Create HTML and validate few pages to see it's ok.
+- Create documention set and make sure no warning is emitted by appledoc.
+- Install documentation set and make sure it's available in Xcode.
+- Publish documentatino set and make sure atom file is updated with new versions and xar file is generated.
+- Update build number with `ruby ~/Dropbox/Scripts/Custom/git-version.rb` (copy result to GBAppledocStringsProvider's appledocData).
+
+This should provide level of quality big enough to ensure the biggest bugs are caught.
+
+
+Major classes and their roles
+=============================
+
+Main classes and top-down overview
+----------------------------------
+
+appledoc run session is managed through `GBAppledocApplication` Main responsibilities of the class are preparing settings for the session by combining factory defaults, global settings and command line switches and starting different generation phases, based on the settings: parsing source files, post processing and comments processing, generation of output files. Each phase relies on results of previous ones, so they need to be connected somehow. To avoid close coupling as well as allow additional phases in the future if need be, classes involved are not connected to each other. Instead a common class - `GBStore` is introduced. This class is a container of all information extracted from source files. Similarly, `GBApplicationSettingsProvider` contains all settings for the application. Both classes are passed around the rest of the application classes:
+
+- `GBAppledocApplication`: Creates `GBApplicationSettingsProvider` with required settings, then creates `GBStore` instance. Then it invokes all phases handling classes as required.
+- `GBParser`: Parses all source code and converts it to various objects which are then registered to `GBStore`. After this class is done, store is ready for post processing. It includes all classes, categories and protocols together with their members, all represented as lists of objects in the store. Additionally, all comments are attached to the objects, but only as source strings at this point.
+- `GBProcessor`: Post processes objects registered to `GBStore`. This phase requires all objects be registered to store so we can detect cross references and similar. This is where categories are merged to classes and all comments strings are converted into object representations among other things. Exact handling can be changed by various settings. The main responsibility of this phase is to prepare clean store, ready for output generation.
+- `GBGenerator`: Uses all objects registered to `GBStore` to generate output as defined by settings.
+
+
+Components covered in unit tests
+================================
+
+Model group
+-----------
+
+All major components are under unit tests:
+
+- GBStore class
+- GBClassData class
+- GBCategoryData class
+- GBProtocolData class
+- GBIvarData class
+- GBMethodData class
+- GBModelBase class
+- GBAdoptedProtocolsProvider class
+- GBIvarsProvider class
+- GBMethodsProvider class
+- GBComment class
+- GBParagraphItems class
+
+Not tested: helper/trivial classes, however these are briefly covered by other unit tests, most often from processing group.
+
+
+Parsing group
+-------------
+
+All major components are under unit tests:
+
+- GBTokenizer class
+- GBObjectiveCParser class
+
+Not tested: GBParser that parses command line arguments and invokes source code and comments parsing. However this is trivial and should be easily verified manually.
+
+
+Processing group
+----------------
+
+All major components are under unit tests:
+
+- GBProcessor
+- GBCommentsProcessor
+
+
+Generating group
+----------------
+
+Only lower level generating components are under unit tests:
+
+- GBTemplateHandler
+- GBTemplateVariablesProvider
+
+As this is where parsed data is converted to output, this layer relies heavily on file system. Although it would be possible to unit test it, it seems like too much effort for too little gain IMHO, so only lower level building blocks are tested. This part requires most manual testing.
View
15 Generating/GBDocSetInstallGenerator.h
@@ -0,0 +1,15 @@
+//
+// GBDocSetInstallGenerator.h
+// appledoc
+//
+// Created by Tomaz Kragelj on 18.1.11.
+// Copyright 2011 Gentle Bytes. All rights reserved.
+//
+
+#import "GBOutputGenerator.h"
+
+/** Concrete `GBOutputGenerator` that installs generated documentation set files to Xcode.
+ */
+@interface GBDocSetInstallGenerator : GBOutputGenerator
+
+@end
View
68 Generating/GBDocSetInstallGenerator.m
@@ -0,0 +1,68 @@
+//
+// GBDocSetInstallGenerator.m
+// appledoc
+//
+// Created by Tomaz Kragelj on 18.1.11.
+// Copyright 2011 Gentle Bytes. All rights reserved.
+//
+
+#import "GBApplicationSettingsProvider.h"
+#import "GBStore.h"
+#import "GBTask.h"
+#import "GBDocSetInstallGenerator.h"
+
+@implementation GBDocSetInstallGenerator
+
+#pragma Generation handling
+
+- (BOOL)generateOutputWithStore:(id)store error:(NSError **)error {
+ NSParameterAssert(self.previousGenerator != nil);
+ GBLogInfo(@"Installing DocSet...");
+
+ // Prepare for run.
+ if (![super generateOutputWithStore:store error:error]) return NO;
+
+ // Prepare source and destination paths and file names.
+ NSString *sourceUserPath = self.inputUserPath;
+ NSString *destUserPath = self.outputUserPath;
+ NSString *sourcePath = [sourceUserPath stringByStandardizingPath];
+ NSString *destPath = [destUserPath stringByStandardizingPath];\
+
+ // Create destination directory and move files to it.
+ GBLogVerbose(@"Moving DocSet files from '%@' to '%@'...", sourceUserPath, destUserPath);
+ if (![self initializeDirectoryAtPath:destUserPath error:error]) {
+ GBLogWarn(@"Failed initializing DocSet installation directory '%@'!", destUserPath);
+ return NO;
+ }
+ if (![self copyOrMoveItemFromPath:sourcePath toPath:destPath error:error]) {
+ GBLogWarn(@"Failed moving DocSet files from '%@' to '%@'!", sourceUserPath, destUserPath);
+ return NO;
+ }
+
+ // Prepare AppleScript for loading the documentation into the Xcode.
+ GBLogVerbose(@"Installing DocSet to Xcode...");
+ NSMutableString* installScript = [NSMutableString string];
+ [installScript appendString:@"tell application \"Xcode\"\n"];
+ [installScript appendFormat:@"\tload documentation set with path \"%@\"\n", destPath];
+ [installScript appendString:@"end tell"];
+
+ // Run the AppleScript for loading the documentation into the Xcode.
+ NSDictionary* errorDict = nil;
+ NSAppleScript* script = [[NSAppleScript alloc] initWithSource:installScript];
+ if (![script executeAndReturnError:&errorDict])
+ {
+ NSString *message = [errorDict objectForKey:NSAppleScriptErrorMessage];
+ if (error) *error = [NSError errorWithCode:GBErrorDocSetXcodeReloadFailed description:@"Documentation set was installed, but couldn't reload documentation within Xcode." reason:message];
+ return NO;
+ }
+ return YES;
+}
+
+#pragma mark Overriden methods
+
+- (NSString *)outputUserPath {
+ // Note that we use custom location, so can't rely on default implementation using outputSubpath!
+ return [self.settings.docsetInstallPath stringByAppendingPathComponent:self.settings.docsetBundleFilename];
+}
+
+@end
View
106 Generating/GBDocSetOutputGenerator.m
@@ -22,8 +22,6 @@ - (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;
@@ -32,7 +30,6 @@ - (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
@@ -57,15 +54,7 @@ - (BOOL)generateOutputWithStore:(id)store error:(NSError **)error {
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 installDocSet:error]) return NO;
-
- // Prepare documentation set for publishing.
- if (!self.settings.publishDocSet) return YES;
- if (![self publishDocSet:error]) return NO;
+ if (![self removeTemporaryFiles:error]) return NO;
return YES;
}
@@ -73,7 +62,7 @@ - (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.
- NSString *sourceFilesPath = [self.previousGenerator.outputUserPath stringByStandardizingPath];
+ NSString *sourceFilesPath = [self.inputUserPath stringByStandardizingPath];
NSString *documentsPath = [self outputPathToTemplateEndingWith:@"documents-template"];
if (!documentsPath) {
if (error) *error = [NSError errorWithCode:GBErrorDocSetDocumentTemplateMissing description:@"Documents template is missing!" reason:@"documents-template file is required to determine location for Documents path in DocSet bundle!"];
@@ -211,97 +200,6 @@ - (BOOL)removeTemporaryFiles:(NSError **)error {
return YES;
}
-- (BOOL)installDocSet:(NSError **)error {
- GBLogInfo(@"Installing DocSet...");
-
- // Prepare source and destination paths and file names.
- NSString *sourceUserPath = self.outputUserPath;
- NSString *destUserPath = self.docsetInstallationPath;
- NSString *sourcePath = [sourceUserPath stringByStandardizingPath];
- NSString *destPath = [destUserPath stringByStandardizingPath];\
-
- // Create destination directory and move files to it.
- GBLogVerbose(@"Moving DocSet files from '%@' to '%@'...", sourceUserPath, destUserPath);
- if (![self initializeDirectoryAtPath:destUserPath error:error]) {
- GBLogWarn(@"Failed initializing DocSet installation directory '%@'!", destUserPath);
- return NO;
- }
- if (![self copyOrMoveItemFromPath:sourcePath toPath:destPath error:error]) {
- GBLogWarn(@"Failed moving DocSet files from '%@' to '%@'!", sourceUserPath, destUserPath);
- return NO;
- }
-
- // Prepare AppleScript for loading the documentation into the Xcode.
- GBLogVerbose(@"Installing DocSet to Xcode...");
- NSMutableString* installScript = [NSMutableString string];
- [installScript appendString:@"tell application \"Xcode\"\n"];
- [installScript appendFormat:@"\tload documentation set with path \"%@\"\n", destPath];
- [installScript appendString:@"end tell"];
-
- // Run the AppleScript for loading the documentation into the Xcode.
- NSDictionary* errorDict = nil;
- NSAppleScript* script = [[NSAppleScript alloc] initWithSource:installScript];
- if (![script executeAndReturnError:&errorDict])
- {
- NSString *message = [errorDict objectForKey:NSAppleScriptErrorMessage];
- if (error) *error = [NSError errorWithCode:GBErrorDocSetXcodeReloadFailed description:@"Documentation set was installed, but couldn't reload documentation within Xcode." reason:message];
- return NO;
- }
- 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 {
View
15 Generating/GBDocSetPublishGenerator.h
@@ -0,0 +1,15 @@
+//
+// GBDocSetPublishGenerator.h
+// appledoc
+//
+// Created by Tomaz Kragelj on 18.1.11.
+// Copyright 2011 Gentle Bytes. All rights reserved.
+//
+
+#import "GBOutputGenerator.h"
+
+/** Concrete `GBOutputGenerator` that prepares installed documentation set files for publishing.
+ */
+@interface GBDocSetPublishGenerator : GBOutputGenerator
+
+@end
View
83 Generating/GBDocSetPublishGenerator.m
@@ -0,0 +1,83 @@
+//
+// GBDocSetPublishGenerator.m
+// appledoc
+//
+// Created by Tomaz Kragelj on 18.1.11.
+// Copyright 2011 Gentle Bytes. All rights reserved.
+//
+
+#import "GBStore.h"
+#import "GBApplicationSettingsProvider.h"
+#import "GBTask.h"
+#import "GBDataObjects.h"
+#import "GBTemplateHandler.h"
+#import "GBDocSetPublishGenerator.h"
+
+@implementation GBDocSetPublishGenerator
+
+#pragma Generation handling
+
+- (BOOL)generateOutputWithStore:(id)store error:(NSError **)error {
+ NSParameterAssert(self.previousGenerator != nil);
+ GBLogInfo(@"Preparing DocSet for publishing...");
+
+ // Prepare for run.
+ if (![super generateOutputWithStore:store error:error]) return NO;
+ 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.inputUserPath;
+ NSString *packageName = self.settings.docsetPackageFilename;
+ NSString *atomName = self.settings.docsetAtomFilename;
+
+ // Prepare command line arguments for packaging.
+ NSString *outputDir = self.outputUserPath;
+ 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];
+
+ // Run the task.
+ 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 Overriden methods
+
+- (NSString *)outputSubpath {
+ return @"publish";
+}
+
+@end
View
6 Generating/GBGenerator.m
@@ -10,6 +10,8 @@
#import "GBApplicationSettingsProvider.h"
#import "GBHTMLOutputGenerator.h"
#import "GBDocSetOutputGenerator.h"
+#import "GBDocSetInstallGenerator.h"
+#import "GBDocSetPublishGenerator.h"
#import "GBGenerator.h"
@interface GBGenerator ()
@@ -58,6 +60,10 @@ - (void)setupGeneratorStepsWithStore:(id)store {
[self.outputGenerators addObject:[GBHTMLOutputGenerator generatorWithSettingsProvider:self.settings]];
if (!self.settings.createDocSet) return;
[self.outputGenerators addObject:[GBDocSetOutputGenerator generatorWithSettingsProvider:self.settings]];
+ if (!self.settings.installDocSet) return;
+ [self.outputGenerators addObject:[GBDocSetInstallGenerator generatorWithSettingsProvider:self.settings]];
+ if (!self.settings.publishDocSet) return;
+ [self.outputGenerators addObject:[GBDocSetPublishGenerator generatorWithSettingsProvider:self.settings]];
}
- (void)runGeneratorStepsWithStore:(id)store {
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:kGBTemplatePlaceholderYear] forKey:@"copyrightDate"];
+ [dict setObject:[self.settings stringByReplacingOccurencesOfPlaceholdersInString:kGBTemplatePlaceholderUpdateDate] forKey:@"lastUpdatedDate"];
}
#pragma mark Properties
View
12 Generating/GBOutputGenerator.h
@@ -153,14 +153,26 @@
This uses the same string as entered by the user when starting the application. Send `stringByStandardizingPath` message to the returned value before using it!
+ @see inputUserPath
@see outputUserPath
*/
@property (readonly) NSString *templateUserPath;
+/** Returns user-friendly input path string.
+
+ This is simply a shortcut for output path of previous generator. Internally it works by sending the `outputUserPath` message to `previousGenerator and returning the result. If previous generator is `nil` (i.e. this is the first generator), `nil` is returned. Send `stringByStandardizingPath` message to the returned value before using it!
+
+
+ @see templateUserPath
+ @see outputUserPath
+ */
+@property (readonly) NSString *inputUserPath;
+
/** Returns the output path including `outputSubpath`.
This uses the same string as entered by the user when starting the application. Send `stringByStandardizingPath` message to the returned value before using it!
+ @see inputUserPath
@see templateUserPath
*/
@property (readonly) NSString *outputUserPath;
View
5 Generating/GBOutputGenerator.m
@@ -238,6 +238,11 @@ - (NSString *)templateUserPath {
return [self.settings.templatesPath stringByAppendingPathComponent:self.outputSubpath];
}
+- (NSString *)inputUserPath {
+ if (!self.previousGenerator) return nil;
+ return self.previousGenerator.outputUserPath;
+}
+
- (NSString *)outputUserPath {
return [self.settings.outputPath stringByAppendingPathComponent:self.outputSubpath];
}
View
12 Parsing/GBTokenizer.m
@@ -50,7 +50,7 @@ - (id)initWithSourceTokenizer:(PKTokenizer *)tokenizer filename:(NSString *)file
if (self) {
self.singleLineCommentRegex = @"(?m-s:\\s*///(.*)$)";
self.multiLineCommentRegex = @"(?s:/\\*\\*(.*)\\*/)";
- self.commentDelimiterRegex = @"^[!@#$%^&*()_=+`~,<.>/?;:'\"-]{3,}";
+ self.commentDelimiterRegex = @"^[!@#$%^&*()_=+`~,<.>/?;:'\"-]{3,}$";
self.tokenIndex = 0;
self.lastCommentBuilder = [NSMutableString string];
self.previousCommentBuilder = [NSMutableString string];
@@ -187,7 +187,6 @@ - (BOOL)consumeComments {
}
// Append string value to current comment and proceed with next token.
- value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[self.lastCommentBuilder appendString:value];
self.tokenIndex++;
}
@@ -229,13 +228,14 @@ - (NSString *)commentValueFromString:(NSString *)value {
}];
}
- // Finally remove common line prefix including all spaces and compose all objects into final comment.
+ // Finally remove common line prefix and a single prefix space (but leave multiple spaces to properly handle space prefixed example blocks!) and compose all objects into final comment.
NSCharacterSet *spacesSet = [NSCharacterSet characterSetWithCharactersInString:@" "];
+ NSString *spacesPrefixRegex = @"^ {2,}";
+ NSString *tabPrefixRegex = @"^\t";
NSMutableString *result = [NSMutableString stringWithCapacity:[value length]];
[comments enumerateObjectsUsingBlock:^(NSString *line, NSUInteger idx, BOOL *stop) {
- if (stripPrefix)
- line = [line stringByReplacingOccurrencesOfRegex:prefixRegex withString:@""];
- line = [line stringByTrimmingCharactersInSet:spacesSet];
+ if (stripPrefix) line = [line stringByReplacingOccurrencesOfRegex:prefixRegex withString:@""];
+ if (![line isMatchedByRegex:spacesPrefixRegex] && ![line isMatchedByRegex:tabPrefixRegex]) line = [line stringByTrimmingCharactersInSet:spacesSet];
[result appendString:line];
if (idx < [comments count] - 1) [result appendString:@"\n"];
}];
View
17 Processing/GBCommentsProcessor.m
@@ -156,7 +156,7 @@ - (BOOL)registerWarningBlockFromlines:(NSArray *)lines {
NSString *string = [NSString stringByCombiningLines:lines delimitWith:@"\n"];
NSString *description = [string stringByMatching:regex capture:1];
if ([description length] == 0) {
- GBLogWarn(@"Empty @warning block found in %@!", self.sourceFileInfo);
+ if (self.settings.warnOnEmptyDescription) GBLogWarn(@"Empty @warning block found at %@!", self.sourceFileInfo);
return YES;
}
GBLogDebug(@" - Found warning block '%@' at %@.", [string normalizedDescription], self.sourceFileInfo);
@@ -185,7 +185,7 @@ - (BOOL)registerBugBlockFromLines:(NSArray *)lines {
NSString *string = [NSString stringByCombiningLines:lines delimitWith:@"\n"];
NSString *description = [string stringByMatching:regex capture:1];
if ([description length] == 0) {
- GBLogWarn(@"Empty @bug block found in %@!", self.sourceFileInfo);
+ if (self.settings.warnOnEmptyDescription) GBLogWarn(@"Empty @bug block found at %@!", self.sourceFileInfo);
return YES;
}
GBLogDebug(@" - Found bug block '%@' at %@.", [string normalizedDescription], self.sourceFileInfo);
@@ -223,8 +223,13 @@ - (BOOL)registerExampleBlockFromLines:(NSArray *)lines {
if ([stringValue length] > 0) [stringValue appendString:@"\n"];
NSString *lineText = [captures objectAtIndex:2];
[stringValue appendString:lineText];
- }];
+ }];
+ if ([stringValue length] == 0) {
+ if (self.settings.warnOnEmptyDescription) GBLogWarn(@"Found empty example block at %@!", self.sourceFileInfo);
+ return YES;
+ }
GBLogDebug(@" - Found example block '%@' at %@.", [stringValue normalizedDescription], self.sourceFileInfo);
+ NSString *escapedHTML = [self.settings stringByEscapingHTML:stringValue];
// If there isn't paragraph registered yet, create one now, otherwise we'll just add the block to previous paragraph.
[self pushParagraphIfStackIsEmpty];
@@ -232,7 +237,7 @@ - (BOOL)registerExampleBlockFromLines:(NSArray *)lines {
// Prepare paragraph item. Note that we don't use paragraphs stack as currently we don't process the text for cross refs!
GBParagraphSpecialItem *item = [GBParagraphSpecialItem specialItemWithType:GBSpecialItemTypeExample stringValue:stringValue];
GBCommentParagraph *paragraph = [GBCommentParagraph paragraph];
- [paragraph registerItem:[GBParagraphTextItem paragraphItemWithStringValue:stringValue]];
+ [paragraph registerItem:[GBParagraphTextItem paragraphItemWithStringValue:escapedHTML]];
[item registerParagraph:paragraph];
// Register example block to current paragraph.
@@ -423,7 +428,7 @@ - (BOOL)registerDirectivesBlockFromLines:(NSArray *)lines {
}
// If the line doesn't contain known directive, warn the user.
- GBLogWarn(@"Found unknown directive '%@' at %@!", directive, sourceInfo);
+ if (self.settings.warnOnUnknownDirective) GBLogWarn(@"Found unknown directive '%@' at %@!", directive, sourceInfo);
}];
return YES;
@@ -483,7 +488,7 @@ - (void)registerTextItemsFromStringToCurrentParagraph:(NSString *)string {
[paragraph registerItem:decorator];
decorator = nil;
} else {
- GBLogWarn(@"Unknown text decorator type %@ detected at %@!", type, self.sourceFileInfo);
+ if (self.settings.warnOnUnknownDirective) GBLogWarn(@"Unknown text decorator type %@ detected at %@!", type, self.sourceFileInfo);
decorator = nil;
}
View
32 Readme.markdown
@@ -15,6 +15,10 @@ Main goals of appledoc:
To make your experience with appledoc as smooth as possible, we warmly suggest reading this whole document as well as all online documentation mentioned in "using appledoc" section below!
+Usage of appledoc is allowed under the terms listed in LICENSE section at the bottom of this file!
+
+Want to keep updated? Follow us on Twitter - [@gentlebytes](http://twitter.com/gentlebytes).
+
Quick install
=============
@@ -62,6 +66,12 @@ Have problems? This is what you can do to troubleshoot:
4. If you think you found a bug or want to request new feature, go to [appledoc issues page](https://github.com/tomaz/appledoc/issues). First read existing issues to see if there is already a request there (if you're using master branch, also read closed issues as your request may have already been covered but isn't yet merged on master branch). You can vote on existing requests to help us decide which features to concetrate on or you can add a comment to aid in solving it. If you don't find the request there, create a new issue; include parts of source files that give you problems if possible and/or description or steps that lead to it.
5. If you're having problems with some of your source files and don't want to publish them online, you can contact us through email below. We'll do our best to help you out, but bear in mind appledoc is not commercial product; it's created and maintaned in our spare time, so resources are limited.
+Developer notes
+---------------
+
+If you wish to contribute, see Developer Notes file for short overview of how appledoc works internally.
+
+
Minimum system requirements
---------------------------
@@ -69,17 +79,27 @@ Minimum system requirements
- OS X 10.6 for running
-LICENCE
+LICENSE
=======
-appledoc is licenced with MIT licence as stated below. Basically you can use it whatever way you wish, including in commercial projects. Although you don't have to, we'd appreciate you link back to us from your product or web page/blog:
+appledoc is licensed with modified BSD license. In plain language: you're allowed to do whatever you wish with the code, modify, redistribute, embed in your products (free or commercial), but you must include copyright, terms of usage and disclaimer as stated in the license, the same way as any other BSD licensed code. You can of course use documentation generated by appledoc for your products (free or commercial), but you must attribute appledoc either in documentation itself or other appropriate place such as your website.
+
+If for whatever reason you cannot agree to these terms, contact us through contact form on [our about page](http://gentlebytes.com/about), we'll do our best to help you out you out and find a workable solution!
+
+
+ Copyright (c) 2009-2011, Gentle Bytes
+ All rights reserved.
+
+ Redistribution and use in source, binary forms and generated documentation, with or without modification, are permitted provided that the following conditions are met:
+
+ - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-Copyright (c) 2009-2010 Gentle Bytes
+ - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ - Redistributions of documentation generated by appledoc must include attribution to appledoc, either in documentation itself or other appropriate media.
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ - Neither the name of the appledoc, Gentle Bytes nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Gentle Bytes appledoc@gentlebytes.com
View
113 Release Notes.markdown
@@ -1,113 +0,0 @@
-What's new
-==========
-
-2.0
----
-
-- HTML respects whitespace from comments.
-- Added support for docset publishing.
-- Added support for preprocessor delimited class definitions.
-- Fixed URL and crossrefs detection when embedded in parenthesis.
-- Fixed . path handling for cmd line options.
-- Added option for keeping intermediate files.
-- Added troubleshooting info to readme.
-- Fixed output directories creation.
-- Fixed few missing @synthesize sentences.
-- Many under the hood fixes and optimizations.
-
-
-2.0b3
------
-
-- Bug fix release for documentation set.
-
-
-2.0b2
------
-
-- Appledoc version is included in HTML footer.
-- Method result can also be specified with @returns.
-- Cross reference to index and hierarchy pages.
-- Class hierarchy output.
-- Clean HTML output.
-- Minor fixes and refactorings.
-
-
-2.0b1
------
-
-- Custom source code and comments parsing instead of doxygen.
-- Embedded template builder instead of XSLT.
-- Complete rewrite.
-
-
-
-
-Release Checklist
-=================
-
-All low level key components are covered with unit tests, however some higher level components aren't so make sure you check all following tests before releasing a version.
-
-- Compile as release to fix missing @synthesize and similar.
-- Make sure all unit tests pass.
-- Validate all input paths are parsed.
-- Create HTML and validate few pages to see it's ok.
-- Create documention set and make sure no warning is emitted by appledoc.
-- Install documentation set and make sure it's available in Xcode.
-
-This should provide level of quality big enough to ensure the biggest bugs are caught.
-
-
-Components covered in unit tests
-================================
-
-Model group
------------
-
-All major components are under unit tests:
-
-- GBStore class
-- GBClassData class
-- GBCategoryData class
-- GBProtocolData class
-- GBIvarData class
-- GBMethodData class
-- GBModelBase class
-- GBAdoptedProtocolsProvider class
-- GBIvarsProvider class
-- GBMethodsProvider class
-- GBComment class
-- GBParagraphItems class
-
-Not tested: helper/trivial classes, however these are briefly covered by other unit tests, most often from processing group.
-
-
-Parsing group
--------------
-
-All major components are under unit tests:
-
-- GBTokenizer class
-- GBObjectiveCParser class
-
-Not tested: GBParser that parses command line arguments and invokes source code and comments parsing. However this is trivial and should be easily verified manually.
-
-
-Processing group
-----------------
-
-All major components are under unit tests:
-
-- GBProcessor
-- GBCommentsProcessor
-
-
-Generating group
-----------------
-
-Only lower level generating components are under unit tests:
-
-- GBTemplateHandler
-- GBTemplateVariablesProvider
-
-As this is where parsed data is converted to output, this layer relies heavily on file system. Although it would be possible to unit test it, it seems like too much effort for too little gain IMHO, so only lower level building blocks are tested. This part requires most manual testing.
View
4 Templates/html/hierarchy-template.html
@@ -4,7 +4,7 @@
<title>{{page/title}}</title>
<meta http-equiv="Content-Type" content="application/xhtml+xml;charset=utf-8" />
<link rel="stylesheet" type="text/css" href="css/styles.css" />
- <meta name="generator" content="{{strings/appledocData/tool}} {{strings/appledocData/version}}" />
+ {{#strings/appledocData}}<meta name="generator" content="{{tool}} {{version}} (build {{build}})" />{{/strings/appledocData}}
</head>
<body>
<article id="contents" role="main">
@@ -53,7 +53,7 @@ <h2 class="index-title">{{strings/hierarchyPage/categoriesTitle}}</h2>
<div class="footer-copyright">
{{#page}}<p><span class="copyright">&copy; {{copyrightDate}} {{copyrightHolder}}. All rights reserved. (Last updated: {{lastUpdatedDate}})</span>{{/page}}<br />
{{#strings/appledocData}}
- <span class="generator">Generated by <a href="{{strings/appledocData/homepage}}">{{tool}} {{version}}/{{build}}</a>.</span></p>
+ <span class="generator">Generated by <a href="{{homepage}}">{{tool}} {{version}} (build {{build}})</a>.</span></p>
{{/strings/appledocData}}
</div>
View
4 Templates/html/index-template.html
@@ -4,7 +4,7 @@
<title>{{page/title}}</title>
<meta http-equiv="Content-Type" content="application/xhtml+xml;charset=utf-8" />
<link rel="stylesheet" type="text/css" href="css/styles.css" />
- <meta name="generator" content="{{strings/appledocData/tool}} {{strings/appledocData/version}}" />
+ {{#strings/appledocData}}<meta name="generator" content="{{tool}} {{version}} (build {{build}})" />{{/strings/appledocData}}
</head>
<body>
<article id="contents" role="main">
@@ -57,7 +57,7 @@ <h2 class="index-title">{{strings/indexPage/categoriesTitle}}</h2>
<div class="footer-copyright">
{{#page}}<p><span class="copyright">&copy; {{copyrightDate}} {{copyrightHolder}}. All rights reserved. (Last updated: {{lastUpdatedDate}})</span>{{/page}}<br />
{{#strings/appledocData}}
- <span class="generator">Generated by <a href="{{strings/appledocData/homepage}}">{{tool}} {{version}}/{{build}}</a>.</span></p>
+ <span class="generator">Generated by <a href="{{homepage}}">{{tool}} {{version}} (build {{build}})</a>.</span></p>
{{/strings/appledocData}}
</div>
View
4 Templates/html/object-template.html
@@ -4,7 +4,7 @@
<title>{{page/title}}</title>
<meta http-equiv="Content-Type" content="application/xhtml+xml;charset=utf-8" />
<link rel="stylesheet" type="text/css" href="../css/styles.css" />
- <meta name="generator" content="{{strings/appledocData/tool}} {{strings/appledocData/version}}" />
+ {{#strings/appledocData}}<meta name="generator" content="{{tool}} {{version}} (build {{build}})" />{{/strings/appledocData}}
</head>
<body>
<article>
@@ -81,7 +81,7 @@ <h2 class="subtitle subtitle-methods">{{strings/objectMethods/propertiesTitle}}<
<div class="footer-copyright">
{{#page}}<p><span class="copyright">&copy; {{copyrightDate}} {{copyrightHolder}}. All rights reserved. (Last updated: {{lastUpdatedDate}})</span>{{/page}}<br />
{{#strings/appledocData}}
- <span class="generator">Generated by <a href="{{strings/appledocData/homepage}}">{{tool}} {{version}}/{{build}}</a>.</span></p>
+ <span class="generator">Generated by <a href="{{homepage}}">{{tool}} {{version}} (build {{build}})</a>.</span></p>
{{/strings/appledocData}}
</div>
</div>
View
18 Testing/GBApplicationTesting.m
@@ -272,6 +272,24 @@ - (void)testWarnOnUndocumentedMember_shouldAssignValueToSettings {
assertThatBool(settings2.warnOnUndocumentedMember, equalToBool(NO));
}
+- (void)testWarnOnEmptyDescription_shouldAssignValueToSettings {
+ // setup & execute
+ GBApplicationSettingsProvider *settings1 = [self settingsByRunningWithArgs:@"--warn-empty-description", nil];
+ GBApplicationSettingsProvider *settings2 = [self settingsByRunningWithArgs:@"--no-warn-empty-description", nil];
+ // verify
+ assertThatBool(settings1.warnOnEmptyDescription, equalToBool(YES));
+ assertThatBool(settings2.warnOnEmptyDescription, equalToBool(NO));
+}
+
+- (void)testWarnOnUnknownDirective_shouldAssignValueToSettings {
+ // setup & execute
+ GBApplicationSettingsProvider *settings1 = [self settingsByRunningWithArgs:@"--warn-unknown-directive", nil];
+ GBApplicationSettingsProvider *settings2 = [self settingsByRunningWithArgs:@"--no-warn-unknown-directive", nil];
+ // verify
+ assertThatBool(settings1.warnOnUnknownDirective, equalToBool(YES));
+ assertThatBool(settings2.warnOnUnknownDirective, equalToBool(NO));
+}
+
- (void)testWarnOnInvalidCrossReference_shouldAssignValueToSettings {
// setup & execute
GBApplicationSettingsProvider *settings1 = [self settingsByRunningWithArgs:@"--warn-invalid-crossref", nil];
View
77 Testing/GBCommentsProcessor-ExamplesTesting.m
@@ -20,7 +20,7 @@ @implementation GBCommentsProcessorExamplesTesting
- (void)testProcessCommentWithStore_shouldAttachExampleToPreviousParagraph {
// setup
- GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry mockSettingsProvider]];
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
GBComment *comment = [GBComment commentWithStringValue:@"Paragraph\n\n\tDescription"];
// execute
[processor processComment:comment withStore:[GBTestObjectsRegistry store]];
@@ -35,7 +35,7 @@ - (void)testProcessCommentWithStore_shouldAttachExampleToPreviousParagraph {
- (void)testProcessCommentWithStore_shouldDetectMultipleLinesDescriptions {
// setup
- GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry mockSettingsProvider]];
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
GBComment *comment = [GBComment commentWithStringValue:@"Paragraph\n\n\tLine1\n\tLine2"];
// execute
[processor processComment:comment withStore:[GBTestObjectsRegistry store]];
@@ -50,7 +50,7 @@ - (void)testProcessCommentWithStore_shouldDetectMultipleLinesDescriptions {
- (void)testProcessCommentWithStore_shouldRemovePrefixTabs {
// setup
- GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry mockSettingsProvider]];
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
GBComment *comment = [GBComment commentWithStringValue:@"Paragraph\n\n\tLine"];
// execute
[processor processComment:comment withStore:[GBTestObjectsRegistry store]];
@@ -65,7 +65,7 @@ - (void)testProcessCommentWithStore_shouldRemovePrefixTabs {
- (void)testProcessCommentWithStore_shouldKeepPrefixTabsAfterFirst {
// setup
- GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry mockSettingsProvider]];
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
GBComment *comment = [GBComment commentWithStringValue:@"Paragraph\n\n\t\tLine1\n\t\t\t\tLine2"];
// execute
[processor processComment:comment withStore:[GBTestObjectsRegistry store]];
@@ -80,7 +80,7 @@ - (void)testProcessCommentWithStore_shouldKeepPrefixTabsAfterFirst {
- (void)testProcessCommentWithStore_shouldKeepEmptyLinesIfPrefixedWithTab {
// setup
- GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry mockSettingsProvider]];
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
GBComment *comment = [GBComment commentWithStringValue:@"Paragraph\n\n\t\tLine1\n\t\n\tLine3"];
// execute
[processor processComment:comment withStore:[GBTestObjectsRegistry store]];
@@ -95,7 +95,7 @@ - (void)testProcessCommentWithStore_shouldKeepEmptyLinesIfPrefixedWithTab {
- (void)testProcessCommentWithStore_shouldCreateParagraphIfNoneSpecifiedBefore {
// setup
- GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry mockSettingsProvider]];
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
GBComment *comment = [GBComment commentWithStringValue:@"\tDescription"];
// execute
[processor processComment:comment withStore:[GBTestObjectsRegistry store]];
@@ -108,11 +108,72 @@ - (void)testProcessCommentWithStore_shouldCreateParagraphIfNoneSpecifiedBefore {
[self assertParagraph:item.specialItemDescription containsItems:[GBParagraphTextItem class], @"Description", nil];
}
+#pragma mark Comments prefixed with spaces
+
+- (void)testProcessCommentWithStore_shouldDetectIfPrefixedWithAtLeastFourSpaces {
+ // setup
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
+ GBComment *comment1 = [GBComment commentWithStringValue:@" Description"];
+ GBComment *comment2 = [GBComment commentWithStringValue:@" Description"];
+ // execute
+ [processor processComment:comment1 withStore:[GBTestObjectsRegistry store]];
+ [processor processComment:comment2 withStore:[GBTestObjectsRegistry store]];
+ // verify
+ GBCommentParagraph *paragraph1 = comment1.firstParagraph;
+ [self assertParagraph:paragraph1 containsItems:[GBParagraphSpecialItem class], GBNULL, nil];
+ GBParagraphSpecialItem *item1 = [paragraph1.paragraphItems objectAtIndex:0];
+ assertThatInteger(item1.specialItemType, equalToInteger(GBSpecialItemTypeExample));
+ [self assertParagraph:item1.specialItemDescription containsItems:[GBParagraphTextItem class], @"Description", nil];
+ GBCommentParagraph *paragraph2 = comment2.firstParagraph;
+ [self assertParagraph:paragraph2 containsItems:[GBParagraphTextItem class], @" Description", nil];
+}
+
+- (void)testProcessCommentWithStore_shouldKeepAllWhitespaceAfterInitialFourSpaces {
+ // setup
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
+ GBComment *comment = [GBComment commentWithStringValue:@" Description"];
+ // execute
+ [processor processComment:comment withStore:[GBTestObjectsRegistry store]];
+ // verify
+ assertThatInteger([[comment paragraphs] count], equalToInteger(1));
+ GBCommentParagraph *paragraph = comment.firstParagraph;
+ [self assertParagraph:paragraph containsItems:[GBParagraphSpecialItem class], GBNULL, nil];
+ GBParagraphSpecialItem *item = [paragraph.paragraphItems objectAtIndex:0];
+ assertThatInteger(item.specialItemType, equalToInteger(GBSpecialItemTypeExample));
+ [self assertParagraph:item.specialItemDescription containsItems:[GBParagraphTextItem class], @" Description", nil];
+}
+
+#pragma mark Special contents parsing
+
+- (void)testProcessCommentWithStore_shouldEscapeHTMLText {
+ // setup
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
+ GBComment *comment = [GBComment commentWithStringValue:@"\t<sometag>\"'&</sometag>"];
+ // execute
+ [processor processComment:comment withStore:[GBTestObjectsRegistry store]];
+ // verify
+ GBCommentParagraph *paragraph = comment.firstParagraph;
+ GBParagraphSpecialItem *item = [paragraph.paragraphItems objectAtIndex:0];
+ [self assertParagraph:item.specialItemDescription containsItems:[GBParagraphTextItem class], @"&lt;sometag&gt;&quot;&apos;&amp;&lt;/sometag&gt;", nil];
+}
+
+- (void)testProcessCommentWithStore_shouldEscapeHTMLComments {
+ // setup
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
+ GBComment *comment = [GBComment commentWithStringValue:@"\t<!-- .... ->"];
+ // execute
+ [processor processComment:comment withStore:[GBTestObjectsRegistry store]];
+ // verify
+ GBCommentParagraph *paragraph = comment.firstParagraph;
+ GBParagraphSpecialItem *item = [paragraph.paragraphItems objectAtIndex:0];
+ [self assertParagraph:item.specialItemDescription containsItems:[GBParagraphTextItem class], @"&lt;!-- .... -&gt;", nil];
+}
+
#pragma mark Requirements before/after testing
- (void)testProcessCommentWithStore_requiresEmptyLineAfterPreviousParagraphItem {
// setup
- GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry mockSettingsProvider]];
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
GBComment *comment = [GBComment commentWithStringValue:@"Paragraph\n\tLine"];
// execute
[processor processComment:comment withStore:[GBTestObjectsRegistry store]];
@@ -124,7 +185,7 @@ - (void)testProcessCommentWithStore_requiresEmptyLineAfterPreviousParagraphItem
- (void)testProcessCommentWithStore_requiresEmptyLineBeforeNextParagraphItem {
// setup
- GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry mockSettingsProvider]];
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
GBComment *comment1 = [GBComment commentWithStringValue:@"\tLine1\nLine2"];
GBComment *comment2 = [GBComment commentWithStringValue:@"\tLine1\n\nLine2"];
// execute
View
18 Testing/GBTokenizerTesting.m
@@ -265,13 +265,27 @@ - (void)testConsumeFromToUsingBlock_shouldQuitWithoutConsumingCurrentToken {
#pragma mark Comments parsing testing
-- (void)testLastCommentString_shouldTrimSpacesFromBothEnds {
+- (void)testLastCommentString_shouldTrimSpacesFromBothEndsIfPrefixedWithSignleSpace {
// setup & execute
- GBTokenizer *tokenizer = [GBTokenizer tokenizerWithSource:[PKTokenizer tokenizerWithString:@"/// comment \n ONE"] filename:@"file"];
+ GBTokenizer *tokenizer = [GBTokenizer tokenizerWithSource:[PKTokenizer tokenizerWithString:@"/// comment \n ONE"] filename:@"file"];
// verify
assertThat([tokenizer.lastComment stringValue], is(@"comment"));
}
+- (void)testLastCommentString_shouldNotTrimSpacesIfPrefixedWithMultipleSpaces {
+ // setup & execute
+ GBTokenizer *tokenizer = [GBTokenizer tokenizerWithSource:[PKTokenizer tokenizerWithString:@"/// comment \n ONE"] filename:@"file"];
+ // verify
+ assertThat([tokenizer.lastComment stringValue], is(@" comment "));
+}
+
+- (void)testLastCommentString_shouldNotTrimSpacesIfPrefixedWithTab {
+ // setup & execute
+ GBTokenizer *tokenizer = [GBTokenizer tokenizerWithSource:[PKTokenizer tokenizerWithString:@"///\tcomment \n ONE"] filename:@"file"];
+ // verify
+ assertThat([tokenizer.lastComment stringValue], is(@"\tcomment "));
+}
+
- (void)testLastCommentString_shouldGroupSingleLineComments {
// setup & execute
GBTokenizer *tokenizer = [GBTokenizer tokenizerWithSource:[PKTokenizer tokenizerWithString:@"/// line1\n/// line2\n ONE"] filename:@"file"];
View
20 appledoc.xcodeproj/project.pbxproj
@@ -35,6 +35,8 @@
73329AA6122E8AA800AEBA2B /* GBCommentsProcessor-OrderedListsTesting.m in Sources */ = {isa = PBXBuildFile; fileRef = 73329AA5122E8AA800AEBA2B /* GBCommentsProcessor-OrderedListsTesting.m */; };
73329B30122EE14900AEBA2B /* GBCommentsProcessor-WarningsTesting.m in Sources */ = {isa = PBXBuildFile; fileRef = 73329B2F122EE14900AEBA2B /* GBCommentsProcessor-WarningsTesting.m */; };
73329B33122EE18C00AEBA2B /* GBParagraphSpecialItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 73329B32122EE18C00AEBA2B /* GBParagraphSpecialItem.m */; };
+ 7335F72B12E58DCC0094F72E /* GBDocSetInstallGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 7335F72A12E58DCC0094F72E /* GBDocSetInstallGenerator.m */; };
+ 7335F72E12E58E160094F72E /* GBDocSetPublishGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 7335F72D12E58E160094F72E /* GBDocSetPublishGenerator.m */; };
73397A2812A5070700EDC035 /* GBTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 73397A2712A5070700EDC035 /* GBTask.m */; };
733E9FDB122BA9B00060CBDE /* GBCommentComponentsProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 733E9FDA122BA9B00060CBDE /* GBCommentComponentsProvider.m */; };
733EA12F122BDD7B0060CBDE /* GHUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 733EA0F1122BDC5B0060CBDE /* GHUnit.framework */; };
@@ -134,6 +136,8 @@
7359B16A129A5A0700F67AD1 /* GRMustacheVariableElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 7359B146129A5A0600F67AD1 /* GRMustacheVariableElement.m */; };
7359B16B129A5A0700F67AD1 /* GRMustacheVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 7359B148129A5A0700F67AD1 /* GRMustacheVersion.m */; };
7359B16C129A5A0700F67AD1 /* GRMustacheVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 7359B148129A5A0700F67AD1 /* GRMustacheVersion.m */; };
+ 736314A912ED7DB100852593 /* GBDocSetInstallGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 7335F72A12E58DCC0094F72E /* GBDocSetInstallGenerator.m */; };
+ 736314AA12ED7DB900852593 /* GBDocSetPublishGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 7335F72D12E58E160094F72E /* GBDocSetPublishGenerator.m */; };
7367298412A3D7A000879D1B /* NSError+GBError.m in Sources */ = {isa = PBXBuildFile; fileRef = 7367298312A3D7A000879D1B /* NSError+GBError.m */; };
7367B84E11FEF496005ED6CD /* GBCategoryData.m in Sources */ = {isa = PBXBuildFile; fileRef = 7367B84D11FEF496005ED6CD /* GBCategoryData.m */; };
7367BB3612003CAB005ED6CD /* GBModelBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 7367BB3512003CAB005ED6CD /* GBModelBase.m */; };
@@ -239,6 +243,10 @@
73329B2F122EE14900AEBA2B /* GBCommentsProcessor-WarningsTesting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GBCommentsProcessor-WarningsTesting.m"; sourceTree = "<group>"; };
73329B31122EE18C00AEBA2B /* GBParagraphSpecialItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBParagraphSpecialItem.h; sourceTree = "<group>"; };
73329B32122EE18C00AEBA2B /* GBParagraphSpecialItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GBParagraphSpecialItem.m; sourceTree = "<group>"; };
+ 7335F72912E58DCC0094F72E /* GBDocSetInstallGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBDocSetInstallGenerator.h; sourceTree = "<group>"; };
+ 7335F72A12E58DCC0094F72E /* GBDocSetInstallGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GBDocSetInstallGenerator.m; sourceTree = "<group>"; };
+ 7335F72C12E58E160094F72E /* GBDocSetPublishGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBDocSetPublishGenerator.h; sourceTree = "<group>"; };
+ 7335F72D12E58E160094F72E /* GBDocSetPublishGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GBDocSetPublishGenerator.m; sourceTree = "<group>"; };
73397A2612A5070700EDC035 /* GBTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBTask.h; sourceTree = "<group>"; };
73397A2712A5070700EDC035 /* GBTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GBTask.m; sourceTree = "<group>"; };
733E9FB8122B9D510060CBDE /* GBCommentTesting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GBCommentTesting.m; sourceTree = "<group>"; };
@@ -385,7 +393,7 @@
73EC015B122852ED0076B7B3 /* GBCommentsProcessor-TextItemsTesting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GBCommentsProcessor-TextItemsTesting.m"; sourceTree = "<group>"; };
73EC016F1228561B0076B7B3 /* GBCommentParagraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBCommentParagraph.h; sourceTree = "<group>"; };
73EC01701228561B0076B7B3 /* GBCommentParagraph.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GBCommentParagraph.m; sourceTree = "<group>"; };
- 73EEB7A812CA2BE700E546DB /* Release Notes.markdown */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Release Notes.markdown"; sourceTree = "<group>"; };
+ 73EEB7A812CA2BE700E546DB /* Developer Notes.markdown */ = {isa = PBXFileReference; path = "Developer Notes.markdown"; sourceTree = "<group>"; };
73F2CA70123E4161009B406B /* GBCommentsProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBCommentsProcessor.h; sourceTree = "<group>"; };
73F2CA71123E4161009B406B /* GBCommentsProcessor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GBCommentsProcessor.m; sourceTree = "<group>"; };
73F2CA72123E4161009B406B /* GBProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBProcessor.h; sourceTree = "<group>"; };
@@ -532,7 +540,7 @@
isa = PBXGroup;
children = (
73EA656912B7944E00398BD1 /* Readme.markdown */,
- 73EEB7A812CA2BE700E546DB /* Release Notes.markdown */,
+ 73EEB7A812CA2BE700E546DB /* Developer Notes.markdown */,
73D54C9011F8D18300CCDDB0 /* Classes */,
739AD36F1254449D00B642C3 /* Templates */,
73D54BDF11F8CE2300CCDDB0 /* Startup */,
@@ -693,6 +701,10 @@
739AD62E1255D8CB00B642C3 /* GBHTMLTemplateVariablesProvider.m */,
731872C312A3B75C0035509F /* GBDocSetOutputGenerator.h */,
731872C412A3B75C0035509F /* GBDocSetOutputGenerator.m */,
+ 7335F72912E58DCC0094F72E /* GBDocSetInstallGenerator.h */,
+ 7335F72A12E58DCC0094F72E /* GBDocSetInstallGenerator.m */,
+ 7335F72C12E58E160094F72E /* GBDocSetPublishGenerator.h */,
+ 7335F72D12E58E160094F72E /* GBDocSetPublishGenerator.m */,
7321D0E512944CF500796DEC /* GBTemplateHandler.h */,
7321D0E612944CF500796DEC /* GBTemplateHandler.m */,
73734616129668340046D6B8 /* GBDictionaryTemplateLoader.h */,
@@ -1135,6 +1147,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 736314AA12ED7DB900852593 /* GBDocSetPublishGenerator.m in Sources */,
+ 736314A912ED7DB100852593 /* GBDocSetInstallGenerator.m in Sources */,
733EA139122BDE980060CBDE /* GHUnitTestMain.m in Sources */,
733EA13E122BDEBD0060CBDE /* GBAdoptedProtocolsProviderTesting.m in Sources */,
733EA13F122BDEBE0060CBDE /* GBCategoryDataTesting.m in Sources */,
@@ -1335,6 +1349,8 @@
731872C512A3B75C0035509F /* GBDocSetOutputGenerator.m in Sources */,
73397A2812A5070700EDC035 /* GBTask.m in Sources */,
732E6CBD12DF02B7009DD6E0 /* NSArray+GBArray.m in Sources */,
+ 7335F72B12E58DCC0094F72E /* GBDocSetInstallGenerator.m in Sources */,
+ 7335F72E12E58E160094F72E /* GBDocSetPublishGenerator.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Please sign in to comment.
Something went wrong with that request. Please try again.