Skip to content

Commit

Permalink
Adds Standard Template and site_name support
Browse files Browse the repository at this point in the history
* Added site_name support
* Standard Template support
* More tests
  • Loading branch information
Kompanez Andreas, ENT-BIZ-PSR-AUG-AUS authored and Kompanez Andreas, ENT-BIZ-PSR-AUG-AUS committed Feb 18, 2016
1 parent 0930851 commit 61fd8bf
Show file tree
Hide file tree
Showing 13 changed files with 287 additions and 38 deletions.
18 changes: 14 additions & 4 deletions Example/LinkPreviewKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@

/* Begin PBXBuildFile section */
29D20A2022924E0FB787BD00 /* libPods-Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 051A10CA141AB60D6E3601A1 /* libPods-Tests.a */; };
458F6AFA1C75B4B100CAAD75 /* t1.html in Resources */ = {isa = PBXBuildFile; fileRef = 458F6AF91C75B4B100CAAD75 /* t1.html */; };
45BE8E961C75CA28009E4A0C /* LKTemplateLibraryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45BE8E951C75CA28009E4A0C /* LKTemplateLibraryTests.m */; };
45F04C591C747B1700A3FADE /* LKLinkPreviewReaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 45F04C581C747B1700A3FADE /* LKLinkPreviewReaderTests.m */; };
45F04C5B1C747BB600A3FADE /* input.html in Resources */ = {isa = PBXBuildFile; fileRef = 45F04C5A1C747BB600A3FADE /* input.html */; };
45F04C5B1C747BB600A3FADE /* t0.html in Resources */ = {isa = PBXBuildFile; fileRef = 45F04C5A1C747BB600A3FADE /* t0.html */; };
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
Expand Down Expand Up @@ -42,8 +44,11 @@
1B603EBB072AEBA89C02B396 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
2BF196D820679E10C0F41C26 /* Pods-LinkPreviewKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LinkPreviewKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LinkPreviewKit/Pods-LinkPreviewKit.debug.xcconfig"; sourceTree = "<group>"; };
2F1DF689B0F4F9C2778A816F /* Pods-LinkPreviewKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LinkPreviewKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-LinkPreviewKit/Pods-LinkPreviewKit.release.xcconfig"; sourceTree = "<group>"; };
458F6AF91C75B4B100CAAD75 /* t1.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = t1.html; sourceTree = "<group>"; };
458F6AFB1C75BF2800CAAD75 /* LKTypes.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = LKTypes.m; path = ../../Pod/Classes/LKTypes.m; sourceTree = "<group>"; };
45BE8E951C75CA28009E4A0C /* LKTemplateLibraryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKTemplateLibraryTests.m; sourceTree = "<group>"; };
45F04C581C747B1700A3FADE /* LKLinkPreviewReaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKLinkPreviewReaderTests.m; sourceTree = "<group>"; };
45F04C5A1C747BB600A3FADE /* input.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = input.html; sourceTree = "<group>"; };
45F04C5A1C747BB600A3FADE /* t0.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = t0.html; sourceTree = "<group>"; };
45F04C5C1C74811C00A3FADE /* LKLinkPreviewHTMLReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LKLinkPreviewHTMLReader.h; path = ../../Pod/Classes/LKLinkPreviewHTMLReader.h; sourceTree = "<group>"; };
45F04C5D1C74811C00A3FADE /* LKLinkPreviewHTMLReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LKLinkPreviewHTMLReader.m; path = ../../Pod/Classes/LKLinkPreviewHTMLReader.m; sourceTree = "<group>"; };
45F04C631C74BF0B00A3FADE /* LKTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LKTypes.h; path = ../../Pod/Classes/LKTypes.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -168,14 +173,16 @@
children = (
6003F5B6195388D20070C39A /* Supporting Files */,
45F04C581C747B1700A3FADE /* LKLinkPreviewReaderTests.m */,
45F04C5A1C747BB600A3FADE /* input.html */,
45BE8E951C75CA28009E4A0C /* LKTemplateLibraryTests.m */,
);
path = Tests;
sourceTree = "<group>";
};
6003F5B6195388D20070C39A /* Supporting Files */ = {
isa = PBXGroup;
children = (
45F04C5A1C747BB600A3FADE /* t0.html */,
458F6AF91C75B4B100CAAD75 /* t1.html */,
6003F5B7195388D20070C39A /* Tests-Info.plist */,
6003F5B8195388D20070C39A /* InfoPlist.strings */,
606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */,
Expand All @@ -197,6 +204,7 @@
isa = PBXGroup;
children = (
45F04C631C74BF0B00A3FADE /* LKTypes.h */,
458F6AFB1C75BF2800CAAD75 /* LKTypes.m */,
BAD3F3301AD922D10022466C /* LKLinkPreview.h */,
BAD3F3311AD922D10022466C /* LKLinkPreview.m */,
BABCB8281AD9247700AE97E1 /* LKLinkPreviewKit.h */,
Expand Down Expand Up @@ -330,8 +338,9 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
458F6AFA1C75B4B100CAAD75 /* t1.html in Resources */,
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */,
45F04C5B1C747BB600A3FADE /* input.html in Resources */,
45F04C5B1C747BB600A3FADE /* t0.html in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -445,6 +454,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
45BE8E961C75CA28009E4A0C /* LKTemplateLibraryTests.m in Sources */,
45F04C591C747B1700A3FADE /* LKLinkPreviewReaderTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
80 changes: 58 additions & 22 deletions Example/Tests/LKLinkPreviewReaderTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,79 @@

#import <HTMLReader/HTMLReader.h>
#import "LKLinkPreviewHTMLReader.h"
#import "LKLinkPreview.h"

static NSArray *testFiles = nil;
static NSString *const extension = @"html";

@interface LKLinkPreviewReaderTests : XCTestCase

@property (nonatomic, copy) NSString *testHTML;
@interface LKLinkPreviewReaderTests : XCTestCase

@end

@implementation LKLinkPreviewReaderTests

- (void)setUp {
- (void)setUp
{
[super setUp];

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *path = [bundle pathForResource:@"input" ofType:@"html"];
NSString *html = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
XCTAssertNotNil(html);
self.testHTML = html;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
testFiles = [NSArray arrayWithObjects:@"t0", @"t1", nil];
});
}

- (void)tearDown {
[super tearDown];

self.testHTML = nil;
}

- (void)testThatTestHTMLLoadsAndIsParseable {
HTMLDocument *document = [HTMLDocument documentWithString:self.testHTML];
XCTAssertNotNil(document);
XCTAssertNotNil(document.rootElement);
- (void)testThatReaderFindAnyPreviews
{
LKLinkPreviewHTMLReader *htmlReader = [LKLinkPreviewHTMLReader new];
for (NSString *file in testFiles) {
HTMLDocument *document = [self loadTestHTMLDocumentWithName:file extension:extension];
XCTAssertNotNil(document);
[htmlReader linkPreviewFromHTMLDocument:document completionHandler:^(NSArray *previews, NSError *error) {
XCTAssertTrue(previews.count >= 1);
}];
}
}

- (void)testThatReaderFindPreviews {
HTMLDocument *document = [HTMLDocument documentWithString:self.testHTML];
- (void)testThatReaderFindOpenGraphPreviews
{
XCTestExpectation *expectation = [self expectationWithDescription:@"OpenGraph previews found"];
__block NSUInteger count = 0;

LKLinkPreviewHTMLReader *htmlReader = [LKLinkPreviewHTMLReader new];
[htmlReader linkPreviewFromHTMLDocument:document completionHandler:^(NSArray *previews, NSError *error) {
XCTAssertTrue(previews.count == 1);
for (NSString *file in testFiles) {
HTMLDocument *document = [self loadTestHTMLDocumentWithName:file extension:extension];
XCTAssertNotNil(document);
[htmlReader linkPreviewFromHTMLDocument:document completionHandler:^(NSArray *previews, NSError *error) {
for (LKLinkPreview *preview in previews) {
if (preview.kind == LKTemplateKindOpenGraph) {
count += 1;
if (count == testFiles.count) {
[expectation fulfill];
}
}
}
}];
}

[self waitForExpectationsWithTimeout:2.0 handler:^(NSError *error) {
if (error) {
XCTFail(@"Couldnt find all OpenGraph previews");
}
}];

}

#pragma mark Helpers

- (HTMLDocument *)loadTestHTMLDocumentWithName:(NSString *)name extension:(NSString *)extension
{
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *path = [bundle pathForResource:name ofType:extension];
NSString *html = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
HTMLDocument *document = [HTMLDocument documentWithString:html];

return document;
}

@end
45 changes: 45 additions & 0 deletions Example/Tests/LKTemplateLibraryTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// LKTemplateLibraryTests.m
// LinkPreviewKit
//
// Created by Andreas Kompanez on 18/02/16.
// Copyright © 2016 Andreas Kompanez. All rights reserved.
//

#import <XCTest/XCTest.h>

#import "LKTemplateLibrary.h"

@interface LKTemplateLibraryTests : XCTestCase

@property (nonatomic) LKTemplateLibrary *library;

@end

@implementation LKTemplateLibraryTests

- (void)setUp {
[super setUp];

self.library = [LKTemplateLibrary new];
}

- (void)testThatRegisteredPreviewsAreSame
{
LKLinkPreview *p0 = [self.library fetchOrRegisterNewLinkPreviewByKind:LKTemplateKindTwitterCard];
LKLinkPreview *p1 = [self.library fetchOrRegisterNewLinkPreviewByKind:LKTemplateKindTwitterCard];
XCTAssertEqual(p0, p1);
}

- (void)testThatResetAndRegisterWorks
{
XCTAssertTrue(self.library.allPreviews.count == 0);
[self.library fetchOrRegisterNewLinkPreviewByKind:LKTemplateKindStandard];
[self.library fetchOrRegisterNewLinkPreviewByKind:LKTemplateKindTwitterCard];
XCTAssertTrue(self.library.allPreviews.count == 2);
[self.library resetRegisteredPreviews];
XCTAssertTrue(self.library.allPreviews.count == 0);
}


@end
File renamed without changes.
64 changes: 64 additions & 0 deletions Example/Tests/t1.html

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Pod/Classes/LKLinkPreview.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) LKTemplateKind kind;
@property (nonatomic, copy) NSString * _Nullable title;
@property (nonatomic, copy) NSString * _Nullable type;
@property (nonatomic, copy) NSString * _Nullable siteName;
@property (nonatomic) NSURL * _Nullable URL;
@property (nonatomic) NSURL * _Nullable imageURL;
@property (nonatomic, copy) NSString * _Nullable linkDescription;
Expand Down
7 changes: 6 additions & 1 deletion Pod/Classes/LKLinkPreview.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
if ([property hasPrefix:namespace]) {
return [property stringByReplacingOccurrencesOfString:namespace withString:@""];
}
return namespace;
return property;
}

@interface LKLinkPreview ()
Expand Down Expand Up @@ -75,6 +75,9 @@ - (void)setContent:(nullable id)content forProperty:(NSString * _Nonnull)propert
else if ([normalized isEqualToString:@"image"]) {
self.imageURL = [NSURL URLWithString:content];
}
else if ([normalized isEqualToString:@"site_name"]) {
self.siteName = content;
}
else if ([normalized isEqualToString:@"description"]) {
self.linkDescription = content;
}
Expand All @@ -83,7 +86,9 @@ - (void)setContent:(nullable id)content forProperty:(NSString * _Nonnull)propert
- (NSString *)description
{
NSMutableString *body = [NSMutableString new];
[body appendFormat:@"kind: '%@'\n", StringFromLKTemplateKind(self.kind)];
[body appendFormat:@"title: '%@'\n", self.title];
[body appendFormat:@"siteName: '%@'\n", self.siteName];
[body appendFormat:@"type: '%@'\n", self.type];
[body appendFormat:@"URL: '%@'\n", [self.URL absoluteString]];
[body appendFormat:@"imageURL: '%@'\n", [self.imageURL absoluteString]];
Expand Down
71 changes: 64 additions & 7 deletions Pod/Classes/LKLinkPreviewHTMLReader.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
#import <HTMLReader/HTMLReader.h>

static NSString *const LKHTMLElementMeta = @"meta";
static NSString *const LKHTMLElementTitle = @"title";
static NSString *const LKHTMLAttributeContent = @"content";
static NSString *const LKHTMLAttributeProperty = @"property";
static NSString *const LKHTMLAttributeName = @"name";

@interface LKLinkPreview (LKLinkPreviewHTMLReader)

Expand All @@ -34,26 +36,75 @@ - (BOOL)isEmpty

@interface LKTemplateMatcher : NSObject

- (LKTemplateKind)matchingTemplateByProperty:(NSString *)property;
- (LKTemplateKind)matchingTemplateByKey:(NSString *)property;

@end

@implementation LKTemplateMatcher

- (LKTemplateKind)matchingTemplateByProperty:(NSString *)property
- (LKTemplateKind)matchingTemplateByKey:(NSString *)property
{
if ([property hasPrefix:@"og:"]) {
return LKTemplateKindOpenGraph;
}
if ([property hasPrefix:@"twitter:"]) {
return LKTemplateKindTwitterCard;
}
if ([property isEqualToString:@"description"]) {
return LKTemplateKindStandard;
}

return LKTemplateKindUndefined;
}

@end

@interface LKMetaKeyValuePair : NSObject

@property (nonatomic, copy) NSString *key;
@property (nonatomic, copy) NSString *value;

@end

@implementation LKMetaKeyValuePair

- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p> key '%@'; value '%@'", [self class], self, self.key, self.value];
}

@end

@interface LKLKMetaKeyValuePairParser : NSObject

- (LKMetaKeyValuePair * _Nonnull)parse:(HTMLElement *)element;

@end

@implementation LKLKMetaKeyValuePairParser

- (LKMetaKeyValuePair *)parse:(HTMLElement *)element
{
NSString *property = [element.attributes objectForKey:LKHTMLAttributeProperty];
NSString *name = [element.attributes objectForKey:LKHTMLAttributeName];
NSString *content = [element.attributes objectForKey:LKHTMLAttributeContent];
NSString *key = nil;

if (property.length > 0 && name.length == 0) {
key = property;
}
else {
key = name;
}
LKMetaKeyValuePair *pair = [LKMetaKeyValuePair new];
pair.key = key;
pair.value = content;

return pair;
}

@end


@implementation LKLinkPreviewHTMLReader

Expand All @@ -62,23 +113,29 @@ - (void)linkPreviewFromHTMLDocument:(HTMLDocument *)document completionHandler:(
NSArray *metaNodes = [document nodesMatchingSelector:LKHTMLElementMeta];
LKTemplateLibrary *library = [LKTemplateLibrary new];
LKTemplateMatcher *matcher = [LKTemplateMatcher new];
LKLKMetaKeyValuePairParser *keyValueParser = [LKLKMetaKeyValuePairParser new];

for (id meta in metaNodes) {
if (! [meta isKindOfClass:[HTMLElement class]]) {
continue;
}
HTMLElement *metaElement = (HTMLElement *)meta;
NSString *property = [metaElement.attributes objectForKey:LKHTMLAttributeProperty];
NSString *content = [metaElement.attributes objectForKey:LKHTMLAttributeContent];

LKTemplateKind kind = [matcher matchingTemplateByProperty:property];
LKMetaKeyValuePair *keyValuePair = [keyValueParser parse:metaElement];
LKTemplateKind kind = [matcher matchingTemplateByKey:keyValuePair.key];

if (kind == LKTemplateKindUndefined) {
continue;
}

LKLinkPreview *preview = [library fetchOrRegisterNewLinkPreviewByKind:kind];
[preview setContent:content forProperty:property];
[preview setContent:keyValuePair.value forProperty:keyValuePair.key];
}

// Check for Standard Template
LKLinkPreview *standardTemplatePreview = [library fetchOrRegisterNewLinkPreviewByKind:LKTemplateKindStandard];
if (standardTemplatePreview) {
HTMLElement *titleElement = [document nodesMatchingSelector:LKHTMLElementTitle].firstObject;
standardTemplatePreview.title = titleElement.textContent;
}

if (handler) {
Expand Down
4 changes: 2 additions & 2 deletions Pod/Classes/LKTemplateLibrary.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
@interface LKTemplateLibrary : NSObject

/// Returns all the registered @c LKLinkPreview objects
@property (nonatomic, readonly) NSArray *allPreviews;
@property (nonatomic, readonly) NSArray * _Nonnull allPreviews;

- (LKLinkPreview *)fetchOrRegisterNewLinkPreviewByKind:(LKTemplateKind)kind;
- (LKLinkPreview * _Nullable)fetchOrRegisterNewLinkPreviewByKind:(LKTemplateKind)kind;

- (void)resetRegisteredPreviews;

Expand Down
Loading

0 comments on commit 61fd8bf

Please sign in to comment.