From 1caf27c2e453b3f91ee818eda783082dd0459414 Mon Sep 17 00:00:00 2001 From: Vjacheslav Volodko Date: Wed, 5 Aug 2015 16:18:04 +0300 Subject: [PATCH 01/15] Added styling per window (needed for app extension support) --- Classy/Parser/CASStyler.h | 6 ++++++ Classy/Parser/CASStyler.m | 19 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Classy/Parser/CASStyler.h b/Classy/Parser/CASStyler.h index 1016fc0..61ccc19 100644 --- a/Classy/Parser/CASStyler.h +++ b/Classy/Parser/CASStyler.h @@ -30,6 +30,12 @@ */ @property (nonatomic, copy) NSString *watchFilePath; +/** + * Windows to update views. + * Needed for live updates when UIApplication is not available (e.g. in Application Extensions) + */ +@property (nonatomic, strong) NSArray *targetWindows; + /** * Set file path location of styling data and report any errors * diff --git a/Classy/Parser/CASStyler.m b/Classy/Parser/CASStyler.m index 0bf6021..185ed69 100644 --- a/Classy/Parser/CASStyler.m +++ b/Classy/Parser/CASStyler.m @@ -114,11 +114,12 @@ - (void)setVariables:(NSDictionary *)variables { if (!self.filePath) return; // if stylesheet has already been loaded. reload stylesheet + NSString *filePath = _filePath; _filePath = nil; - self.filePath = _filePath; + self.filePath = filePath; // reapply styles - for (UIWindow *window in UIApplication.sharedApplication.windows) { + for (UIWindow *window in self.updatedWindows) { [self styleSubviewsOfView:window]; } } @@ -706,6 +707,18 @@ - (CASObjectClassDescriptor *)objectClassDescriptorForClass:(Class)aClass { return objectClassDescriptor; } +- (NSArray *)updatedWindows +{ + NSMutableArray *windows = [NSMutableArray new]; + if (UIApplication.sharedApplication.windows != nil) { + [windows addObjectsFromArray:UIApplication.sharedApplication.windows]; + } + if (self.targetWindows) { + [windows addObjectsFromArray:self.targetWindows]; + } + return windows; +} + #pragma mark - sceduling - (void)updateScheduledItems { @@ -753,7 +766,7 @@ - (void)reloadOnChangesToFilePath:(NSString *)filePath { self.filePath = _watchFilePath; // reapply styles - for (UIWindow *window in UIApplication.sharedApplication.windows) { + for (UIWindow *window in self.updatedWindows) { [self styleSubviewsOfView:window]; } }); From de2c4fd4b3817db6cdb7a1319d2b983a9f0d3fb8 Mon Sep 17 00:00:00 2001 From: Gerasimenko Mike Date: Tue, 18 Aug 2015 15:16:07 +0200 Subject: [PATCH 02/15] Added support for system fonts with weight specification --- Classy/Parser/CASStyleProperty.m | 21 ++++++++++++++++++- .../CASSimpleFormViewController.m | 6 ++++++ .../ClassyExample/Stylesheets/stylesheet.cas | 7 ++++++- Tests/Specs/Unit Tests/CASStylePropertySpec.m | 20 ++++++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/Classy/Parser/CASStyleProperty.m b/Classy/Parser/CASStyleProperty.m index 60e4b6d..1898b2a 100644 --- a/Classy/Parser/CASStyleProperty.m +++ b/Classy/Parser/CASStyleProperty.m @@ -300,7 +300,26 @@ - (BOOL)transformValuesToUIFont:(UIFont **)font { } else { CGFloat fontSizeValue = [fontSize floatValue] ?: [UIFont systemFontSize]; if (fontName) { - *font = [UIFont fontWithName:fontName size:fontSizeValue]; + if ([fontName hasPrefix:@"System"]) { + + NSString *weightString = @"Regular"; + NSArray *nameComponents = [fontName componentsSeparatedByString:@"-"]; + if (nameComponents.count == 2) { + weightString = nameComponents[1]; + } + + if ([weightString isEqualToString:@"Regular"]) { + *font = [UIFont systemFontOfSize:fontSizeValue]; + } + else { + UIFont *systemFont = [UIFont systemFontOfSize:fontSizeValue]; + UIFontDescriptor *descriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:@{UIFontDescriptorFaceAttribute: weightString, UIFontDescriptorFamilyAttribute: systemFont.familyName}]; + *font = [UIFont fontWithDescriptor:descriptor size:fontSizeValue]; + } + } + else { + *font = [UIFont fontWithName:fontName size:fontSizeValue]; + } } else { *font = [UIFont systemFontOfSize:fontSizeValue]; } diff --git a/Example/ClassyExample/CASSimpleFormViewController.m b/Example/ClassyExample/CASSimpleFormViewController.m index 6d9a795..1a48ce1 100644 --- a/Example/ClassyExample/CASSimpleFormViewController.m +++ b/Example/ClassyExample/CASSimpleFormViewController.m @@ -31,6 +31,12 @@ - (void)viewDidLoad { v.backgroundColor = [UIColor redColor]; v.cas_styleClass = @"shadow-view"; [self.view addSubview:v]; + + UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 300, self.view.bounds.size.width - 100, 300)]; + textLabel.text = @"Quick lazy Swift jumps over the lazy iOS/OS X developer's leg."; + textLabel.numberOfLines = 0; + textLabel.cas_styleClass = @"text-label"; + [self.view addSubview:textLabel]; } @end diff --git a/Example/ClassyExample/Stylesheets/stylesheet.cas b/Example/ClassyExample/Stylesheets/stylesheet.cas index 492f7e4..df112c0 100644 --- a/Example/ClassyExample/Stylesheets/stylesheet.cas +++ b/Example/ClassyExample/Stylesheets/stylesheet.cas @@ -15,4 +15,9 @@ UIView.shadow-view { shadow-opacity 1 shadow-color black shadow-offset 0,0 -} \ No newline at end of file +} + +UILabel.text-label { + font: System-Medium 30; + backgroundColor: white; +} diff --git a/Tests/Specs/Unit Tests/CASStylePropertySpec.m b/Tests/Specs/Unit Tests/CASStylePropertySpec.m index db99654..117e322 100644 --- a/Tests/Specs/Unit Tests/CASStylePropertySpec.m +++ b/Tests/Specs/Unit Tests/CASStylePropertySpec.m @@ -322,6 +322,26 @@ - (void)testFont { expect(font.pointSize).to.equal(24.0f); } +- (void)testSystemFont { + NSArray *valueTokens = CASTokensFromString(@"System 12"); + + CASStyleProperty *prop = [[CASStyleProperty alloc]initWithNameToken:nil valueTokens:valueTokens]; + __block UIFont *font = nil; + expect([prop transformValuesToUIFont:&font]).to.beTruthy(); + expect(font.familyName).to.equal([UIFont systemFontOfSize:12].familyName); + expect(font.pointSize).to.equal(12); +} + +- (void)testSystemFontWeight { + NSArray *valueTokens = CASTokensFromString(@"System-Medium 18"); + + CASStyleProperty *prop = [[CASStyleProperty alloc]initWithNameToken:nil valueTokens:valueTokens]; + __block UIFont *font = nil; + expect([prop transformValuesToUIFont:&font]).to.beTruthy(); + expect([font.fontDescriptor.fontAttributes[UIFontDescriptorNameAttribute] rangeOfString:@"Medium"].location != NSNotFound).to.beTruthy(); + expect(font.pointSize).to.equal(18); +} + - (void)testPreferredFontForTextStyle { NSArray *valueTokens = CASTokensFromString(@"body"); From 9e0dc725c74523782e723294b9ea47f62b012224 Mon Sep 17 00:00:00 2001 From: Gerasimenko Mike Date: Wed, 2 Sep 2015 11:25:28 +0200 Subject: [PATCH 03/15] Initialize Classy manually --- Carthage/Build | 1 + Classy/Additions/UIBarItem+CASAdditions.h | 2 +- Classy/Additions/UIBarItem+CASAdditions.m | 2 +- Classy/Additions/UINavigationItem+CASAdditions.h | 2 +- Classy/Additions/UINavigationItem+CASAdditions.m | 4 ++-- Classy/Additions/UITextField+CASAdditions.h | 2 +- Classy/Additions/UITextField+CASAdditions.m | 2 +- Classy/Additions/UIView+CASAdditions.h | 1 + Classy/Additions/UIView+CASAdditions.m | 2 +- Classy/Additions/UIViewController+CASAdditions.h | 2 +- Classy/Additions/UIViewController+CASAdditions.m | 2 +- Classy/Parser/CASStyler.h | 2 ++ Classy/Parser/CASStyler.m | 15 +++++++++++++++ 13 files changed, 29 insertions(+), 10 deletions(-) create mode 120000 Carthage/Build diff --git a/Carthage/Build b/Carthage/Build new file mode 120000 index 0000000..76f9ba2 --- /dev/null +++ b/Carthage/Build @@ -0,0 +1 @@ +../../../../Carthage/Build \ No newline at end of file diff --git a/Classy/Additions/UIBarItem+CASAdditions.h b/Classy/Additions/UIBarItem+CASAdditions.h index 4886a88..89f96f0 100644 --- a/Classy/Additions/UIBarItem+CASAdditions.h +++ b/Classy/Additions/UIBarItem+CASAdditions.h @@ -10,7 +10,7 @@ #import "CASStyleableItem.h" @interface UIBarItem (CASAdditions) - ++ (void)bootstrapClassy; @property (nonatomic, weak, readwrite) id cas_parent; @end diff --git a/Classy/Additions/UIBarItem+CASAdditions.m b/Classy/Additions/UIBarItem+CASAdditions.m index 9c337bb..9be9ec4 100644 --- a/Classy/Additions/UIBarItem+CASAdditions.m +++ b/Classy/Additions/UIBarItem+CASAdditions.m @@ -19,7 +19,7 @@ @implementation UIBarItem (CASAdditions) CASSynthesize(weak, id, cas_parent, setCas_parent); -+ (void)load { ++ (void)bootstrapClassy { [self cas_swizzleInstanceSelector:@selector(init) withNewSelector:@selector(cas_init)]; } diff --git a/Classy/Additions/UINavigationItem+CASAdditions.h b/Classy/Additions/UINavigationItem+CASAdditions.h index f7bfd5e..600998d 100644 --- a/Classy/Additions/UINavigationItem+CASAdditions.h +++ b/Classy/Additions/UINavigationItem+CASAdditions.h @@ -9,5 +9,5 @@ #import @interface UINavigationItem (CASAdditions) - ++ (void)bootstrapClassy; @end diff --git a/Classy/Additions/UINavigationItem+CASAdditions.m b/Classy/Additions/UINavigationItem+CASAdditions.m index e8cba36..90e9a09 100644 --- a/Classy/Additions/UINavigationItem+CASAdditions.m +++ b/Classy/Additions/UINavigationItem+CASAdditions.m @@ -13,7 +13,7 @@ @implementation UINavigationItem (CASAdditions) -+ (void)load { ++ (void)bootstrapClassy { [self cas_swizzleInstanceSelector:@selector(setRightBarButtonItem:animated:) withNewSelector:@selector(cas_setRightBarButtonItem:animated:)]; [self cas_swizzleInstanceSelector:@selector(setLeftBarButtonItem:animated:) withNewSelector:@selector(cas_setLeftBarButtonItem:animated:)]; @@ -45,4 +45,4 @@ - (void)cas_setLeftBarButtonItems:(NSArray *)items animated:(BOOL)animated { [self cas_setLeftBarButtonItems:items animated:animated]; } -@end \ No newline at end of file +@end diff --git a/Classy/Additions/UITextField+CASAdditions.h b/Classy/Additions/UITextField+CASAdditions.h index 8286733..6fb2830 100644 --- a/Classy/Additions/UITextField+CASAdditions.h +++ b/Classy/Additions/UITextField+CASAdditions.h @@ -9,7 +9,7 @@ #import @interface UITextField (CASAdditions) - ++ (void)bootstrapClassy; @property (nonatomic, assign) UIEdgeInsets cas_textEdgeInsets; @end diff --git a/Classy/Additions/UITextField+CASAdditions.m b/Classy/Additions/UITextField+CASAdditions.m index 6ec4f28..db2fd4c 100644 --- a/Classy/Additions/UITextField+CASAdditions.m +++ b/Classy/Additions/UITextField+CASAdditions.m @@ -12,7 +12,7 @@ @implementation UITextField (CASAdditions) -+ (void)load { ++ (void)bootstrapClassy { [self cas_swizzleInstanceSelector:@selector(textRectForBounds:) withNewSelector:@selector(cas_textRectForBounds:)]; diff --git a/Classy/Additions/UIView+CASAdditions.h b/Classy/Additions/UIView+CASAdditions.h index fa65cd3..d2a9109 100644 --- a/Classy/Additions/UIView+CASAdditions.h +++ b/Classy/Additions/UIView+CASAdditions.h @@ -10,6 +10,7 @@ #import "CASStyleableItem.h" @interface UIView (CASAdditions) ++ (void)bootstrapClassy; @property (nonatomic, weak, readwrite) id cas_alternativeParent; @property (nonatomic, copy) IBInspectable NSString *cas_styleClass; diff --git a/Classy/Additions/UIView+CASAdditions.m b/Classy/Additions/UIView+CASAdditions.m index 01db597..41b271d 100644 --- a/Classy/Additions/UIView+CASAdditions.m +++ b/Classy/Additions/UIView+CASAdditions.m @@ -21,7 +21,7 @@ @implementation UIView (CASAdditions) CASSynthesize(weak, id, cas_alternativeParent, setCas_alternativeParent); -+ (void)load { ++ (void)bootstrapClassy { [self cas_swizzleInstanceSelector:@selector(didMoveToWindow) withNewSelector:@selector(cas_didMoveToWindow)]; } diff --git a/Classy/Additions/UIViewController+CASAdditions.h b/Classy/Additions/UIViewController+CASAdditions.h index ef1aa0a..d19fc1a 100644 --- a/Classy/Additions/UIViewController+CASAdditions.h +++ b/Classy/Additions/UIViewController+CASAdditions.h @@ -10,5 +10,5 @@ #import "CASStyleableItem.h" @interface UIViewController (CASAdditions) - ++ (void)bootstrapClassy; @end diff --git a/Classy/Additions/UIViewController+CASAdditions.m b/Classy/Additions/UIViewController+CASAdditions.m index 25bae95..1895459 100644 --- a/Classy/Additions/UIViewController+CASAdditions.m +++ b/Classy/Additions/UIViewController+CASAdditions.m @@ -19,7 +19,7 @@ @implementation UIViewController (CASAdditions) -+ (void)load { ++ (void)bootstrapClassy { [self cas_swizzleInstanceSelector:@selector(setView:) withNewSelector:@selector(cas_setView:)]; } diff --git a/Classy/Parser/CASStyler.h b/Classy/Parser/CASStyler.h index 61ccc19..e859f0b 100644 --- a/Classy/Parser/CASStyler.h +++ b/Classy/Parser/CASStyler.h @@ -12,6 +12,8 @@ @interface CASStyler : NSObject ++ (void)bootstrapClassy; + /** * Singleton instance */ diff --git a/Classy/Parser/CASStyler.m b/Classy/Parser/CASStyler.m index 185ed69..666b1d4 100644 --- a/Classy/Parser/CASStyler.m +++ b/Classy/Parser/CASStyler.m @@ -1,3 +1,4 @@ + // // CASStyler.m // Classy @@ -16,6 +17,12 @@ #import "NSString+CASAdditions.h" #import "CASTextAttributes.h" #import "CASInvocation.h" + +#import "UIBarItem+CASAdditions.h" +#import "UINavigationItem+CASAdditions.h" +#import "UITextField+CASAdditions.h" +#import "UIView+CASAdditions.h" +#import "UIViewController+CASAdditions.h" #import // http://www.cocoawithlove.com/2010/01/getting-subclasses-of-objective-c-class.html @@ -67,6 +74,14 @@ + (instancetype)defaultStyler { return _defaultStyler; } ++ (void)bootstrapClassy { + [UIBarItem bootstrapClassy]; + [UINavigationItem bootstrapClassy]; + [UITextField bootstrapClassy]; + [UIView bootstrapClassy]; + [UIViewController bootstrapClassy]; +} + - (id)init { self = [super init]; if (!self) return nil; From 9e58d03d3a2ee31a9f449a10dcaffac3cda5e4cf Mon Sep 17 00:00:00 2001 From: Gerasimenko Mike Date: Wed, 2 Sep 2015 15:47:14 +0200 Subject: [PATCH 04/15] NSCoding support --- Classy/Parser/CASDeviceOSVersionItem.m | 16 +++++++++++++ Classy/Parser/CASDeviceScreenSizeItem.m | 23 ++++++++++++++---- Classy/Parser/CASDeviceSelector.h | 2 +- Classy/Parser/CASDeviceSelector.m | 14 +++++++++++ Classy/Parser/CASDeviceSelectorItem.h | 4 ++-- Classy/Parser/CASDeviceTypeItem.m | 14 +++++++++++ Classy/Parser/CASStyleNode.h | 2 +- Classy/Parser/CASStyleNode.m | 19 +++++++++++++++ Classy/Parser/CASStyleProperty.h | 2 +- Classy/Parser/CASStyleProperty.m | 24 +++++++++++++++++++ Classy/Parser/CASStyleSelector.h | 2 +- Classy/Parser/CASStyleSelector.m | 30 ++++++++++++++++++++++++ Classy/Parser/CASStyler.m | 16 ++++++++++--- Classy/Parser/CASToken.h | 2 +- Classy/Parser/CASToken.m | 31 +++++++++++++++++++++++++ Tests/Specs/Unit Tests/CASParserSpec.m | 19 ++++++++++++++- Tests/Specs/Unit Tests/CASTokenSpec.m | 18 +++++++++++++- 17 files changed, 222 insertions(+), 16 deletions(-) diff --git a/Classy/Parser/CASDeviceOSVersionItem.m b/Classy/Parser/CASDeviceOSVersionItem.m index 2ae827c..5d886a4 100644 --- a/Classy/Parser/CASDeviceOSVersionItem.m +++ b/Classy/Parser/CASDeviceOSVersionItem.m @@ -34,4 +34,20 @@ - (NSString *)stringValue { return [NSString stringWithFormat:@"(version:%@%@)", [CASDeviceSelector stringFromRelation:self.relation], self.version]; } +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (nil != self) { + self.relation = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(relation))]; + self.version = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(version))]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeInteger:self.relation forKey:NSStringFromSelector(@selector(relation))]; + [aCoder encodeObject:self.version forKey:NSStringFromSelector(@selector(version))]; +} + @end diff --git a/Classy/Parser/CASDeviceScreenSizeItem.m b/Classy/Parser/CASDeviceScreenSizeItem.m index a6d2f53..02b95dc 100644 --- a/Classy/Parser/CASDeviceScreenSizeItem.m +++ b/Classy/Parser/CASDeviceScreenSizeItem.m @@ -5,9 +5,7 @@ #import "CASDeviceScreenSizeItem.h" -@implementation CASDeviceScreenSizeItem { - -} +@implementation CASDeviceScreenSizeItem - (BOOL)isValid { CGSize screenSize = [[UIScreen mainScreen] bounds].size; @@ -41,5 +39,22 @@ - (NSString *)stringValue { return [NSString stringWithFormat:@"(screen-%@:%@%.0f)", dimensionString, [CASDeviceSelector stringFromRelation:self.relation], self.value]; } +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (nil != self) { + self.relation = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(relation))]; + self.value = [aDecoder decodeFloatForKey:NSStringFromSelector(@selector(value))]; + self.dimension = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(dimension))]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeInteger:self.relation forKey:NSStringFromSelector(@selector(relation))]; + [aCoder encodeFloat:self.value forKey:NSStringFromSelector(@selector(value))]; + [aCoder encodeInteger:self.dimension forKey:NSStringFromSelector(@selector(dimension))]; +} -@end \ No newline at end of file +@end diff --git a/Classy/Parser/CASDeviceSelector.h b/Classy/Parser/CASDeviceSelector.h index 1dfdeae..fc7e347 100644 --- a/Classy/Parser/CASDeviceSelector.h +++ b/Classy/Parser/CASDeviceSelector.h @@ -15,7 +15,7 @@ typedef NS_ENUM(NSUInteger, CASDeviceSelectorScreenDimension) { CASDeviceSelectorScreenDimensionHeight, }; -@interface CASDeviceSelector : NSObject +@interface CASDeviceSelector : NSObject @property (nonatomic, strong, readonly) NSArray *items; diff --git a/Classy/Parser/CASDeviceSelector.m b/Classy/Parser/CASDeviceSelector.m index 7a91a11..06f802a 100644 --- a/Classy/Parser/CASDeviceSelector.m +++ b/Classy/Parser/CASDeviceSelector.m @@ -135,4 +135,18 @@ + (NSString *)stringFromRelation:(CASRelation)relation { } } +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (nil != self) { + _items = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(items))]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.items forKey:NSStringFromSelector(@selector(items))]; +} + @end diff --git a/Classy/Parser/CASDeviceSelectorItem.h b/Classy/Parser/CASDeviceSelectorItem.h index ad065bf..645fb9d 100644 --- a/Classy/Parser/CASDeviceSelectorItem.h +++ b/Classy/Parser/CASDeviceSelectorItem.h @@ -17,9 +17,9 @@ typedef NS_ENUM(NSInteger, CASRelation) { CASRelationUndefined = NSNotFound, }; -@protocol CASDeviceSelectorItem +@protocol CASDeviceSelectorItem - (BOOL)isValid; - (NSString *)stringValue; -@end \ No newline at end of file +@end diff --git a/Classy/Parser/CASDeviceTypeItem.m b/Classy/Parser/CASDeviceTypeItem.m index 13e5c55..ac8cf47 100644 --- a/Classy/Parser/CASDeviceTypeItem.m +++ b/Classy/Parser/CASDeviceTypeItem.m @@ -25,4 +25,18 @@ - (NSString *)stringValue { return @"pad"; } +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (nil != self) { + self.deviceType = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(deviceType))]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeInteger:self.deviceType forKey:NSStringFromSelector(@selector(deviceType))]; +} + @end diff --git a/Classy/Parser/CASStyleNode.h b/Classy/Parser/CASStyleNode.h index 377d368..488e287 100644 --- a/Classy/Parser/CASStyleNode.h +++ b/Classy/Parser/CASStyleNode.h @@ -11,7 +11,7 @@ #import "CASStyleSelector.h" #import "CASDeviceSelector.h" -@interface CASStyleNode : NSObject +@interface CASStyleNode : NSObject /** * NSInvocations to apply to appropriate view diff --git a/Classy/Parser/CASStyleNode.m b/Classy/Parser/CASStyleNode.m index 64f5ba5..f616fab 100644 --- a/Classy/Parser/CASStyleNode.m +++ b/Classy/Parser/CASStyleNode.m @@ -27,4 +27,23 @@ - (void)addStyleProperty:(CASStyleProperty *)styleProperty { [_styleProperties addObject:styleProperty]; } +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (nil != self) { + self.invocations = nil; + _styleProperties = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(styleProperties))]; + self.styleSelector = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(styleSelector))]; + self.deviceSelector = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(deviceSelector))]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.styleProperties forKey:NSStringFromSelector(@selector(styleProperties))]; + [aCoder encodeObject:self.styleSelector forKey:NSStringFromSelector(@selector(styleSelector))]; + [aCoder encodeObject:self.deviceSelector forKey:NSStringFromSelector(@selector(deviceSelector))]; +} + @end diff --git a/Classy/Parser/CASStyleProperty.h b/Classy/Parser/CASStyleProperty.h index f9c40f8..59ba336 100644 --- a/Classy/Parser/CASStyleProperty.h +++ b/Classy/Parser/CASStyleProperty.h @@ -10,7 +10,7 @@ #import #import "CASToken.h" -@interface CASStyleProperty : NSObject +@interface CASStyleProperty : NSObject /** * Name of the receiver diff --git a/Classy/Parser/CASStyleProperty.m b/Classy/Parser/CASStyleProperty.m index 1898b2a..854fc2b 100644 --- a/Classy/Parser/CASStyleProperty.m +++ b/Classy/Parser/CASStyleProperty.m @@ -350,4 +350,28 @@ - (void)addChildStyleProperty:(CASStyleProperty *)styleProperty { [_childStyleProperties addObject:styleProperty]; } +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (nil != self) { + self.name = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(name))]; + self.values = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(values))]; + self.nameToken = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(nameToken))]; + self.valueTokens = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(valueTokens))]; + _childStyleProperties = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(childStyleProperties))]; + self.arguments = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(arguments))]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.name forKey:NSStringFromSelector(@selector(name))]; + [aCoder encodeObject:self.values forKey:NSStringFromSelector(@selector(values))]; + [aCoder encodeObject:self.nameToken forKey:NSStringFromSelector(@selector(nameToken))]; + [aCoder encodeObject:self.valueTokens forKey:NSStringFromSelector(@selector(valueTokens))]; + [aCoder encodeObject:_childStyleProperties forKey:NSStringFromSelector(@selector(childStyleProperties))]; + [aCoder encodeObject:self.arguments forKey:NSStringFromSelector(@selector(arguments))]; +} + @end diff --git a/Classy/Parser/CASStyleSelector.h b/Classy/Parser/CASStyleSelector.h index afc28cb..4c69b07 100644 --- a/Classy/Parser/CASStyleSelector.h +++ b/Classy/Parser/CASStyleSelector.h @@ -9,7 +9,7 @@ #import #import "CASStyleableItem.h" -@interface CASStyleSelector : NSObject +@interface CASStyleSelector : NSObject /** * Class of View to match diff --git a/Classy/Parser/CASStyleSelector.m b/Classy/Parser/CASStyleSelector.m index bc270dc..7711f4b 100644 --- a/Classy/Parser/CASStyleSelector.m +++ b/Classy/Parser/CASStyleSelector.m @@ -150,4 +150,34 @@ - (BOOL)matchesItem:(id)item { return YES; } +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + + if (nil != self) { + self.objectClass = NSClassFromString([aDecoder decodeObjectForKey:NSStringFromSelector(@selector(objectClass))]); + self.styleClass = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(objectClass))]; + self.shouldSelectSubclasses = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(shouldSelectSubclasses))]; + self.shouldSelectIndirectSuperview = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(shouldSelectIndirectSuperview))]; + self.parent = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(isParent))]; + self.shouldConcatToParent = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(shouldConcatToParent))]; + self.arguments = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(arguments))]; + self.parentSelector = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(parentSelector))]; + } + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:NSStringFromClass(self.objectClass) forKey:NSStringFromSelector(@selector(objectClass))]; + [aCoder encodeObject:self.styleClass forKey:NSStringFromSelector(@selector(styleClass))]; + [aCoder encodeBool:self.shouldSelectSubclasses forKey:NSStringFromSelector(@selector(shouldSelectSubclasses))]; + [aCoder encodeBool:self.shouldSelectIndirectSuperview forKey:NSStringFromSelector(@selector(shouldSelectIndirectSuperview))]; + [aCoder encodeBool:self.parent forKey:NSStringFromSelector(@selector(isParent))]; + [aCoder encodeBool:self.shouldConcatToParent forKey:NSStringFromSelector(@selector(shouldConcatToParent))]; + [aCoder encodeObject:self.arguments forKey:NSStringFromSelector(@selector(arguments))]; + [aCoder encodeObject:self.parentSelector forKey:NSStringFromSelector(@selector(parentSelector))]; +} + @end diff --git a/Classy/Parser/CASStyler.m b/Classy/Parser/CASStyler.m index 666b1d4..6748ebe 100644 --- a/Classy/Parser/CASStyler.m +++ b/Classy/Parser/CASStyler.m @@ -154,8 +154,18 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { self.styleClassIndex = [NSMutableDictionary new]; self.objectClassIndex = [NSMutableDictionary new]; - CASParser *parser = [CASParser parserFromFilePath:filePath variables:self.variables error:error]; - NSArray *styleNodes = parser.styleNodes; + NSArray *styleNodes = nil; + NSSet *importedFileNames = nil; + + if ([[filePath pathExtension] isEqualToString:@"bcas"]) { + styleNodes = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + importedFileNames = [NSSet set]; + } + else { + CASParser *parser = [CASParser parserFromFilePath:filePath variables:self.variables error:error]; + styleNodes = parser.styleNodes; + importedFileNames = parser.importedFileNames; + } if (self.watchFilePath) { for (dispatch_source_t source in self.fileWatchers) { @@ -164,7 +174,7 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { [self.fileWatchers removeAllObjects]; [self reloadOnChangesToFilePath:self.watchFilePath]; NSString *directoryPath = [self.watchFilePath stringByDeletingLastPathComponent]; - for (NSString *fileName in parser.importedFileNames) { + for (NSString *fileName in importedFileNames) { NSString *resolvedPath = [directoryPath stringByAppendingPathComponent:fileName]; [self reloadOnChangesToFilePath:resolvedPath]; } diff --git a/Classy/Parser/CASToken.h b/Classy/Parser/CASToken.h index f73f15a..f28630d 100644 --- a/Classy/Parser/CASToken.h +++ b/Classy/Parser/CASToken.h @@ -32,7 +32,7 @@ typedef NS_ENUM(NSInteger, CASTokenType) { CASTokenTypeSelector, }; -@interface CASToken : NSObject +@interface CASToken : NSObject /** * The type of the token, may not represent the true type which is determined in context of other tokens diff --git a/Classy/Parser/CASToken.m b/Classy/Parser/CASToken.m index c56496d..b0c2c2b 100644 --- a/Classy/Parser/CASToken.m +++ b/Classy/Parser/CASToken.m @@ -139,4 +139,35 @@ - (BOOL)isPossiblySelectorDelimiter{ return self.type == CASTokenTypeLeftCurlyBrace || self.type == CASTokenTypeIndent; } +- (BOOL)isEqual:(id)object +{ + if ([object isKindOfClass:[CASToken class]]) { + CASToken *other = object; + + return other.type == self.type && ([other.value isEqual:self.value] || other.value == self.value) && other.lineNumber == self.lineNumber; + } + else { + return NO; + } +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (self != nil) { + self.type = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(type))]; + self.value = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(value))]; + self.lineNumber = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(lineNumber))]; + } + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeInteger:self.type forKey:NSStringFromSelector(@selector(type))]; + [aCoder encodeObject:self.value forKey:NSStringFromSelector(@selector(value))]; + [aCoder encodeInteger:self.lineNumber forKey:NSStringFromSelector(@selector(lineNumber))]; +} + @end diff --git a/Tests/Specs/Unit Tests/CASParserSpec.m b/Tests/Specs/Unit Tests/CASParserSpec.m index ff6f2b4..39dd63b 100644 --- a/Tests/Specs/Unit Tests/CASParserSpec.m +++ b/Tests/Specs/Unit Tests/CASParserSpec.m @@ -611,4 +611,21 @@ - (void)testVariablesBasic { expect(node.deviceSelector.stringValue).to.beNil(); } -SpecEnd \ No newline at end of file +- (void)testNSCoding { + NSError *error = nil; + NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"Properties-Nested.cas" ofType:nil]; + NSArray *styles = [CASParser parserFromFilePath:filePath variables:nil error:&error].styleNodes; + expect(error).to.beNil(); + + expect(styles).to.haveCountOf(3); + + NSData *serializedStyles = [NSKeyedArchiver archivedDataWithRootObject:styles]; + expect(serializedStyles).notTo.beNil(); + + NSArray *deserializedStyles = [NSKeyedUnarchiver unarchiveObjectWithData:serializedStyles]; + expect(deserializedStyles).notTo.beNil(); + + expect(styles.count).to.equal(deserializedStyles.count); +} + +SpecEnd diff --git a/Tests/Specs/Unit Tests/CASTokenSpec.m b/Tests/Specs/Unit Tests/CASTokenSpec.m index 4ab37f4..9a9f60b 100644 --- a/Tests/Specs/Unit Tests/CASTokenSpec.m +++ b/Tests/Specs/Unit Tests/CASTokenSpec.m @@ -48,4 +48,20 @@ - (void)testReturnTokenDescription { expect([token description]).to.equal(@"color"); } -SpecEnd \ No newline at end of file +- (void)testCodingAndDecoding { + CASToken *tokenNewline = [CASToken tokenOfType:CASTokenTypeNewline]; + CASToken *tokenColor = [CASToken tokenOfType:CASTokenTypeColor]; + tokenColor.value = [UIColor colorWithWhite:0.5f alpha:0.5f]; + CASToken *tokenString = [CASToken tokenOfType:CASTokenTypeString]; + tokenString.value = @"A string"; + + NSArray *tokensArray = @[tokenColor, tokenNewline, tokenString]; + + NSData *serizlizedTokensArray = [NSKeyedArchiver archivedDataWithRootObject:tokensArray]; + + NSArray *tokensArrayDeserialized = [NSKeyedUnarchiver unarchiveObjectWithData:serizlizedTokensArray]; + + expect(tokensArray).to.equal(tokensArrayDeserialized); +} + +SpecEnd From 5d422105799db517c521b46a92827050f1c7d3b2 Mon Sep 17 00:00:00 2001 From: Gerasimenko Mike Date: Thu, 3 Sep 2015 12:12:42 +0200 Subject: [PATCH 05/15] Cache binary CAS --- Classy/Parser/CASStyleSelector.m | 2 +- Classy/Parser/CASStyler.m | 50 ++++++++++++++++++- .../ClassyExample.xcodeproj/project.pbxproj | 20 ++++++-- Example/ClassyExample/CASAppDelegate.m | 4 +- .../ClassyExample/Stylesheets/stylesheet.cas | 2 +- Tests/ClassyTests.xcodeproj/project.pbxproj | 32 ++++++++---- 6 files changed, 90 insertions(+), 20 deletions(-) diff --git a/Classy/Parser/CASStyleSelector.m b/Classy/Parser/CASStyleSelector.m index 7711f4b..9812eaf 100644 --- a/Classy/Parser/CASStyleSelector.m +++ b/Classy/Parser/CASStyleSelector.m @@ -157,7 +157,7 @@ - (id)initWithCoder:(NSCoder *)aDecoder { if (nil != self) { self.objectClass = NSClassFromString([aDecoder decodeObjectForKey:NSStringFromSelector(@selector(objectClass))]); - self.styleClass = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(objectClass))]; + self.styleClass = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(styleClass))]; self.shouldSelectSubclasses = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(shouldSelectSubclasses))]; self.shouldSelectIndirectSuperview = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(shouldSelectIndirectSuperview))]; self.parent = [aDecoder decodeBoolForKey:NSStringFromSelector(@selector(isParent))]; diff --git a/Classy/Parser/CASStyler.m b/Classy/Parser/CASStyler.m index 6748ebe..8239282 100644 --- a/Classy/Parser/CASStyler.m +++ b/Classy/Parser/CASStyler.m @@ -24,6 +24,7 @@ #import "UIView+CASAdditions.h" #import "UIViewController+CASAdditions.h" #import +#import // http://www.cocoawithlove.com/2010/01/getting-subclasses-of-objective-c-class.html NSArray *ClassGetSubclasses(Class parentClass) { @@ -49,6 +50,27 @@ return result; } +@interface NSData(MD5) + +- (NSString *)generateMD5Hash; + +@end + +@implementation NSData(MD5) + +- (NSString *)generateMD5Hash +{ + unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH]; + CC_MD5(self.bytes, (CC_LONG)self.length, md5Buffer); + NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; + for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) + [output appendFormat:@"%02x",md5Buffer[i]]; + + return output; +} + +@end + @interface CASStyler () @property (nonatomic, strong) NSMutableArray *styleNodes; @@ -157,14 +179,38 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { NSArray *styleNodes = nil; NSSet *importedFileNames = nil; - if ([[filePath pathExtension] isEqualToString:@"bcas"]) { - styleNodes = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + NSMutableData *fileData = [NSMutableData dataWithContentsOfFile:filePath]; + [fileData appendData:[NSKeyedArchiver archivedDataWithRootObject:self.variables]]; + + NSString *casHash = [fileData generateMD5Hash]; + + NSArray* cachePathArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString* cachePath = [cachePathArray lastObject]; + NSString *bcasPath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-%@.bcas", [filePath stringByDeletingPathExtension], casHash]]; + + + NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:bcasPath error:error]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:bcasPath] && [fileAttributes[NSFileSize] integerValue] != 0) { + styleNodes = [NSKeyedUnarchiver unarchiveObjectWithFile:bcasPath]; importedFileNames = [NSSet set]; } else { CASParser *parser = [CASParser parserFromFilePath:filePath variables:self.variables error:error]; styleNodes = parser.styleNodes; importedFileNames = parser.importedFileNames; + + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:parser.styleNodes]; + error = nil; + [[NSFileManager defaultManager] createDirectoryAtPath:[bcasPath stringByDeletingLastPathComponent] + withIntermediateDirectories:YES + attributes:nil + error:error]; + + if (error != nil) { + NSLog(@"Error: cannot create folder %@", [bcasPath stringByDeletingLastPathComponent]); + } + [data writeToFile:bcasPath atomically:YES]; } if (self.watchFilePath) { diff --git a/Example/ClassyExample.xcodeproj/project.pbxproj b/Example/ClassyExample.xcodeproj/project.pbxproj index cc22a16..a921767 100644 --- a/Example/ClassyExample.xcodeproj/project.pbxproj +++ b/Example/ClassyExample.xcodeproj/project.pbxproj @@ -24,8 +24,9 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 136384E66419452BA007511C /* Pods-ClassyExample.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyExample.xcconfig"; path = "../Pods/Pods-ClassyExample.xcconfig"; sourceTree = ""; }; 4E506421190EF2F8003A03B0 /* Ball.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Ball.png; sourceTree = ""; }; + A3C8221728799761B99AE9BD /* Pods-ClassyExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyExample.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-ClassyExample/Pods-ClassyExample.debug.xcconfig"; sourceTree = ""; }; + BB716E9DB58A99D4756CD771 /* Pods-ClassyExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyExample.release.xcconfig"; path = "../Pods/Target Support Files/Pods-ClassyExample/Pods-ClassyExample.release.xcconfig"; sourceTree = ""; }; DD355BDA183E9CD30071E543 /* variables.cas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = variables.cas; sourceTree = ""; }; DD61F4431816370F004A8777 /* stylesheet.cas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = stylesheet.cas; sourceTree = ""; }; DDAB25671814BBBB00F3DAAE /* ClassyExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ClassyExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -72,6 +73,15 @@ name = Images; sourceTree = ""; }; + B100602FAA9CDE99D59C2194 /* Pods */ = { + isa = PBXGroup; + children = ( + A3C8221728799761B99AE9BD /* Pods-ClassyExample.debug.xcconfig */, + BB716E9DB58A99D4756CD771 /* Pods-ClassyExample.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; DD61F4421816370F004A8777 /* Stylesheets */ = { isa = PBXGroup; children = ( @@ -87,7 +97,7 @@ DDAB25701814BBBB00F3DAAE /* ClassyExample */, DDAB25691814BBBB00F3DAAE /* Frameworks */, DDAB25681814BBBB00F3DAAE /* Products */, - 136384E66419452BA007511C /* Pods-ClassyExample.xcconfig */, + B100602FAA9CDE99D59C2194 /* Pods */, ); sourceTree = ""; }; @@ -218,7 +228,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/../Pods/Pods-ClassyExample-resources.sh\"\n"; + shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-ClassyExample/Pods-ClassyExample-resources.sh\"\n"; showEnvVarsInLog = 0; }; 501B6904610449669F2F8026 /* Check Pods Manifest.lock */ = { @@ -341,7 +351,7 @@ }; DDAB25941814BBBB00F3DAAE /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 136384E66419452BA007511C /* Pods-ClassyExample.xcconfig */; + baseConfigurationReference = A3C8221728799761B99AE9BD /* Pods-ClassyExample.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; @@ -356,7 +366,7 @@ }; DDAB25951814BBBB00F3DAAE /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 136384E66419452BA007511C /* Pods-ClassyExample.xcconfig */; + baseConfigurationReference = BB716E9DB58A99D4756CD771 /* Pods-ClassyExample.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; diff --git a/Example/ClassyExample/CASAppDelegate.m b/Example/ClassyExample/CASAppDelegate.m index e00fcd5..6a41a96 100644 --- a/Example/ClassyExample/CASAppDelegate.m +++ b/Example/ClassyExample/CASAppDelegate.m @@ -13,7 +13,9 @@ @implementation CASAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - + [CASStyler bootstrapClassy]; + + [[CASStyler defaultStyler] setVariables:@{@"$accent": @"#ff0000"}]; #if TARGET_IPHONE_SIMULATOR // get absolute file path of stylesheet, using relative path diff --git a/Example/ClassyExample/Stylesheets/stylesheet.cas b/Example/ClassyExample/Stylesheets/stylesheet.cas index df112c0..189bc94 100644 --- a/Example/ClassyExample/Stylesheets/stylesheet.cas +++ b/Example/ClassyExample/Stylesheets/stylesheet.cas @@ -6,7 +6,7 @@ UITableView UILabel { } ^UIViewController > UIView { - background-color: blue; + background-color: $accent; } UIView.shadow-view { diff --git a/Tests/ClassyTests.xcodeproj/project.pbxproj b/Tests/ClassyTests.xcodeproj/project.pbxproj index d7f94d0..5998824 100644 --- a/Tests/ClassyTests.xcodeproj/project.pbxproj +++ b/Tests/ClassyTests.xcodeproj/project.pbxproj @@ -74,10 +74,12 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 079339911EDA90D0E7C07ECD /* Pods-ClassyTestsLoader.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyTestsLoader.release.xcconfig"; path = "../Pods/Target Support Files/Pods-ClassyTestsLoader/Pods-ClassyTestsLoader.release.xcconfig"; sourceTree = ""; }; 13B648C088D7485783343464 /* libPods-ClassyTestsLoader.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ClassyTestsLoader.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 34BACA8D71A54943A4505935 /* Pods-ClassyTestsLoader.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyTestsLoader.xcconfig"; path = "../Pods/Pods-ClassyTestsLoader.xcconfig"; sourceTree = ""; }; 4ED0F9A1198B465600C9FE2C /* UIKit-MultipleClasses.cas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "UIKit-MultipleClasses.cas"; sourceTree = ""; }; - 5548B765C39C4F0FA776C911 /* Pods-ClassyTests.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyTests.xcconfig"; path = "../Pods/Pods-ClassyTests.xcconfig"; sourceTree = ""; }; + 6974873D3DC5638F91AF7A18 /* Pods-ClassyTestsLoader.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyTestsLoader.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-ClassyTestsLoader/Pods-ClassyTestsLoader.debug.xcconfig"; sourceTree = ""; }; + B70022280A544A8418F356ED /* Pods-ClassyTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyTests.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-ClassyTests/Pods-ClassyTests.debug.xcconfig"; sourceTree = ""; }; + BAA4DBC31A8D4B53D68A49E5 /* Pods-ClassyTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyTests.release.xcconfig"; path = "../Pods/Target Support Files/Pods-ClassyTests/Pods-ClassyTests.release.xcconfig"; sourceTree = ""; }; C594C855E67D4ABAAB9D8034 /* libPods-ClassyTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ClassyTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; DD10AD2E1819FA6800A5B71D /* CustomView-Basic.cas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "CustomView-Basic.cas"; sourceTree = ""; }; DD10AD2F1819FA6800A5B71D /* Properties-Basic.cas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Properties-Basic.cas"; sourceTree = ""; }; @@ -170,6 +172,17 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + CB3DB70017F85796C2A240ED /* Pods */ = { + isa = PBXGroup; + children = ( + B70022280A544A8418F356ED /* Pods-ClassyTests.debug.xcconfig */, + BAA4DBC31A8D4B53D68A49E5 /* Pods-ClassyTests.release.xcconfig */, + 6974873D3DC5638F91AF7A18 /* Pods-ClassyTestsLoader.debug.xcconfig */, + 079339911EDA90D0E7C07ECD /* Pods-ClassyTestsLoader.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; DD10AD3E181A16EA00A5B71D /* Integration Tests */ = { isa = PBXGroup; children = ( @@ -262,8 +275,7 @@ DDBF585A18113C850059B8D3 /* Supporting Files */, DDD3D48B1810D6DA00E378A2 /* Frameworks */, DDD3D48A1810D6DA00E378A2 /* Products */, - 5548B765C39C4F0FA776C911 /* Pods-ClassyTests.xcconfig */, - 34BACA8D71A54943A4505935 /* Pods-ClassyTestsLoader.xcconfig */, + CB3DB70017F85796C2A240ED /* Pods */, ); sourceTree = ""; }; @@ -443,7 +455,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/../Pods/Pods-ClassyTestsLoader-resources.sh\"\n"; + shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-ClassyTestsLoader/Pods-ClassyTestsLoader-resources.sh\"\n"; showEnvVarsInLog = 0; }; 85CB2FDD53654D26A4128DD4 /* Check Pods Manifest.lock */ = { @@ -488,7 +500,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/../Pods/Pods-ClassyTests-resources.sh\"\n"; + shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-ClassyTests/Pods-ClassyTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -539,7 +551,7 @@ /* Begin XCBuildConfiguration section */ DDBF584318113BC10059B8D3 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5548B765C39C4F0FA776C911 /* Pods-ClassyTests.xcconfig */; + baseConfigurationReference = B70022280A544A8418F356ED /* Pods-ClassyTests.debug.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ClassyTestsLoader.app/ClassyTestsLoader"; @@ -563,7 +575,7 @@ }; DDBF584418113BC10059B8D3 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5548B765C39C4F0FA776C911 /* Pods-ClassyTests.xcconfig */; + baseConfigurationReference = BAA4DBC31A8D4B53D68A49E5 /* Pods-ClassyTests.release.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ClassyTestsLoader.app/ClassyTestsLoader"; @@ -657,7 +669,7 @@ }; DDD3D4B61810D6DA00E378A2 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 34BACA8D71A54943A4505935 /* Pods-ClassyTestsLoader.xcconfig */; + baseConfigurationReference = 6974873D3DC5638F91AF7A18 /* Pods-ClassyTestsLoader.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; @@ -674,7 +686,7 @@ }; DDD3D4B71810D6DA00E378A2 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 34BACA8D71A54943A4505935 /* Pods-ClassyTestsLoader.xcconfig */; + baseConfigurationReference = 079339911EDA90D0E7C07ECD /* Pods-ClassyTestsLoader.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; From bd7be37f1334e07ef92d915f00dd40e14c5b453b Mon Sep 17 00:00:00 2001 From: Gerasimenko Mike Date: Thu, 3 Sep 2015 14:33:23 +0200 Subject: [PATCH 06/15] Fixed bcas path creation bug --- Classy/Parser/CASStyler.m | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Classy/Parser/CASStyler.m b/Classy/Parser/CASStyler.m index 8239282..1ec083e 100644 --- a/Classy/Parser/CASStyler.m +++ b/Classy/Parser/CASStyler.m @@ -186,11 +186,12 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { NSArray* cachePathArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString* cachePath = [cachePathArray lastObject]; - NSString *bcasPath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-%@.bcas", [filePath stringByDeletingPathExtension], casHash]]; + NSString *bcasPath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-%@.bcas", [[filePath lastPathComponent] stringByDeletingPathExtension], casHash]]; + NSError *fileSystemError = nil; - NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:bcasPath error:error]; - + NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:bcasPath error:nil]; + if ([[NSFileManager defaultManager] fileExistsAtPath:bcasPath] && [fileAttributes[NSFileSize] integerValue] != 0) { styleNodes = [NSKeyedUnarchiver unarchiveObjectWithFile:bcasPath]; importedFileNames = [NSSet set]; @@ -201,14 +202,15 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { importedFileNames = parser.importedFileNames; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:parser.styleNodes]; - error = nil; + [[NSFileManager defaultManager] createDirectoryAtPath:[bcasPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil - error:error]; + error:&fileSystemError]; - if (error != nil) { + if (fileSystemError != nil) { NSLog(@"Error: cannot create folder %@", [bcasPath stringByDeletingLastPathComponent]); + fileSystemError = nil; } [data writeToFile:bcasPath atomically:YES]; } From 600d0c8c5dbc3402ecceb2962037a6ade5855ce1 Mon Sep 17 00:00:00 2001 From: Marco Conti Date: Mon, 21 Sep 2015 19:09:02 +0200 Subject: [PATCH 07/15] Ability to create archives --- Classy.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classy.xcodeproj/project.pbxproj b/Classy.xcodeproj/project.pbxproj index 12d9a91..8e2fb8f 100644 --- a/Classy.xcodeproj/project.pbxproj +++ b/Classy.xcodeproj/project.pbxproj @@ -581,7 +581,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Classy; - SKIP_INSTALL = YES; + SKIP_INSTALL = NO; }; name = Debug; }; @@ -596,7 +596,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Classy; - SKIP_INSTALL = YES; + SKIP_INSTALL = NO; }; name = Release; }; From f97785c0ec5c334222edef4750fff224c3db7dff Mon Sep 17 00:00:00 2001 From: Vjacheslav Volodko Date: Wed, 4 Nov 2015 17:02:48 +0100 Subject: [PATCH 08/15] Moved to app extension secure APIs. --- Classy.xcodeproj/project.pbxproj | 2 ++ Classy/Parser/CASStyler.h | 2 +- Classy/Parser/CASStyler.m | 20 +++++--------------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Classy.xcodeproj/project.pbxproj b/Classy.xcodeproj/project.pbxproj index 8e2fb8f..964e683 100644 --- a/Classy.xcodeproj/project.pbxproj +++ b/Classy.xcodeproj/project.pbxproj @@ -573,6 +573,7 @@ 1EC7195A1B67AE9D00700A14 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -588,6 +589,7 @@ 1EC7195B1B67AE9D00700A14 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; diff --git a/Classy/Parser/CASStyler.h b/Classy/Parser/CASStyler.h index e859f0b..5cc9149 100644 --- a/Classy/Parser/CASStyler.h +++ b/Classy/Parser/CASStyler.h @@ -12,7 +12,7 @@ @interface CASStyler : NSObject -+ (void)bootstrapClassy; ++ (void)bootstrapClassyWithTargetWindows:(NSArray *)targetWindows; /** * Singleton instance diff --git a/Classy/Parser/CASStyler.m b/Classy/Parser/CASStyler.m index 666b1d4..f1dba5b 100644 --- a/Classy/Parser/CASStyler.m +++ b/Classy/Parser/CASStyler.m @@ -74,12 +74,14 @@ + (instancetype)defaultStyler { return _defaultStyler; } -+ (void)bootstrapClassy { ++ (void)bootstrapClassyWithTargetWindows:(NSArray *)targetWindows { [UIBarItem bootstrapClassy]; [UINavigationItem bootstrapClassy]; [UITextField bootstrapClassy]; [UIView bootstrapClassy]; [UIViewController bootstrapClassy]; + + [[self defaultStyler] setTargetWindows:targetWindows]; } - (id)init { @@ -134,7 +136,7 @@ - (void)setVariables:(NSDictionary *)variables { self.filePath = filePath; // reapply styles - for (UIWindow *window in self.updatedWindows) { + for (UIWindow *window in self.targetWindows) { [self styleSubviewsOfView:window]; } } @@ -722,18 +724,6 @@ - (CASObjectClassDescriptor *)objectClassDescriptorForClass:(Class)aClass { return objectClassDescriptor; } -- (NSArray *)updatedWindows -{ - NSMutableArray *windows = [NSMutableArray new]; - if (UIApplication.sharedApplication.windows != nil) { - [windows addObjectsFromArray:UIApplication.sharedApplication.windows]; - } - if (self.targetWindows) { - [windows addObjectsFromArray:self.targetWindows]; - } - return windows; -} - #pragma mark - sceduling - (void)updateScheduledItems { @@ -781,7 +771,7 @@ - (void)reloadOnChangesToFilePath:(NSString *)filePath { self.filePath = _watchFilePath; // reapply styles - for (UIWindow *window in self.updatedWindows) { + for (UIWindow *window in self.targetWindows) { [self styleSubviewsOfView:window]; } }); From 9133afe2d8f215f2919824f61187f751aac7a94d Mon Sep 17 00:00:00 2001 From: Vjacheslav Volodko Date: Wed, 4 Nov 2015 17:06:03 +0100 Subject: [PATCH 09/15] Fixed complier warnings (removed deprecated APIs) --- Classy/Parser/CASStyler.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Classy/Parser/CASStyler.m b/Classy/Parser/CASStyler.m index f1dba5b..6141844 100644 --- a/Classy/Parser/CASStyler.m +++ b/Classy/Parser/CASStyler.m @@ -433,10 +433,10 @@ - (void)setupObjectClassDescriptors { }; NSDictionary *barMetricsMap = @{ - @"default" : @(UIBarMetricsDefault), - @"landscapePhone" : @(UIBarMetricsLandscapePhone), - @"defaultPrompt" : @(UIBarMetricsDefaultPrompt), - @"landscapePhonePrompt" : @(UIBarMetricsLandscapePhonePrompt), + @"default" : @(UIBarMetricsDefault), + @"compact" : @(UIBarMetricsCompact), + @"defaultPrompt" : @(UIBarMetricsDefaultPrompt), + @"compactPrompt" : @(UIBarMetricsCompactPrompt), }; NSDictionary *searchBarIconMap = @{ From 2fd73908678d80e1fdc0e9ee0156a13094d1bfe6 Mon Sep 17 00:00:00 2001 From: Vjacheslav Volodko Date: Wed, 4 Nov 2015 17:06:23 +0100 Subject: [PATCH 10/15] Moved to recomended build settings --- Classy.xcodeproj/project.pbxproj | 5 ++++- .../xcshareddata/xcschemes/Classy.xcscheme | 13 ++++++++----- Classy/Supporting Files/Info.plist | 2 +- .../xcschemes/ClassyExample.xcscheme | 19 ++++++++++++------- .../xcschemes/ClassyTests.xcscheme | 19 ++++++++++++------- 5 files changed, 37 insertions(+), 21 deletions(-) diff --git a/Classy.xcodeproj/project.pbxproj b/Classy.xcodeproj/project.pbxproj index 964e683..8d9fb20 100644 --- a/Classy.xcodeproj/project.pbxproj +++ b/Classy.xcodeproj/project.pbxproj @@ -383,7 +383,7 @@ 1EC7193A1B67AE9D00700A14 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0640; + LastUpgradeCheck = 0710; ORGANIZATIONNAME = "Zeta Project Berlin Gmbh"; TargetAttributes = { 1EC719421B67AE9D00700A14 = { @@ -504,6 +504,7 @@ CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -581,6 +582,7 @@ INFOPLIST_FILE = "Classy/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "wearezeta.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = Classy; SKIP_INSTALL = NO; }; @@ -597,6 +599,7 @@ INFOPLIST_FILE = "Classy/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "wearezeta.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = Classy; SKIP_INSTALL = NO; }; diff --git a/Classy.xcodeproj/xcshareddata/xcschemes/Classy.xcscheme b/Classy.xcodeproj/xcshareddata/xcschemes/Classy.xcscheme index 8c1d1f3..1c58907 100644 --- a/Classy.xcodeproj/xcshareddata/xcschemes/Classy.xcscheme +++ b/Classy.xcodeproj/xcshareddata/xcschemes/Classy.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> + + CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - wearezeta.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Example/ClassyExample.xcodeproj/xcshareddata/xcschemes/ClassyExample.xcscheme b/Example/ClassyExample.xcodeproj/xcshareddata/xcschemes/ClassyExample.xcscheme index 58ad262..cd892da 100644 --- a/Example/ClassyExample.xcodeproj/xcshareddata/xcschemes/ClassyExample.xcscheme +++ b/Example/ClassyExample.xcodeproj/xcshareddata/xcschemes/ClassyExample.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -48,17 +48,21 @@ ReferencedContainer = "container:ClassyExample.xcodeproj"> + + - + - + + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -48,17 +48,21 @@ ReferencedContainer = "container:ClassyTests.xcodeproj"> + + - + - + Date: Thu, 5 Nov 2015 11:21:21 +0100 Subject: [PATCH 11/15] Updated readme file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aa5e66e..6ca7211 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#Classy [![Build Status](https://travis-ci.org/cloudkite/Classy.svg?branch=master)](https://travis-ci.org/cloudkite/Classy) [![Coverage Status](https://img.shields.io/coveralls/cloudkite/Classy.svg)](https://coveralls.io/r/cloudkite/Classy?branch=master) +#Classy [![Build Status](https://travis-ci.org/cloudkite/Classy.svg?branch=master)](https://travis-ci.org/cloudkite/Classy) [![Coverage Status](https://img.shields.io/coveralls/cloudkite/Classy.svg)](https://coveralls.io/r/cloudkite/Classy?branch=master) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) Not CSS. Instead of trying to force UIKit to fit CSS syntax, properties, conventions and constructs. Classy is a stylesheet system built from the ground up to work in harmony with UIKit. It borrows the best ideas from CSS and introduces new syntax, conventions and constructs where appropriate. From d1b2ad5de07b6312e6b6d728d53b9f223a36e88d Mon Sep 17 00:00:00 2001 From: Gerasimenko Mike Date: Wed, 2 Mar 2016 16:44:35 +0100 Subject: [PATCH 12/15] Fixed binary cas caching --- Classy.xcodeproj/project.pbxproj | 8 ++++ Classy/Additions/NSDictionary+KeyValues.h | 14 +++++++ Classy/Additions/NSDictionary+KeyValues.m | 30 ++++++++++++++ Classy/Classy.h | 2 + Classy/Parser/CASStyler.m | 48 +++++++++++++++++------ Classy/Parser/CASUtilities.h | 2 +- 6 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 Classy/Additions/NSDictionary+KeyValues.h create mode 100644 Classy/Additions/NSDictionary+KeyValues.m diff --git a/Classy.xcodeproj/project.pbxproj b/Classy.xcodeproj/project.pbxproj index 8d9fb20..888566f 100644 --- a/Classy.xcodeproj/project.pbxproj +++ b/Classy.xcodeproj/project.pbxproj @@ -81,6 +81,8 @@ 1EC719F41B67AF9C00700A14 /* CASPropertyDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EC719AA1B67AF9C00700A14 /* CASPropertyDescriptor.m */; }; 1EC719F51B67AF9C00700A14 /* CASRuntimeExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC719AB1B67AF9C00700A14 /* CASRuntimeExtensions.h */; }; 1EC719F61B67AF9C00700A14 /* CASRuntimeExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EC719AC1B67AF9C00700A14 /* CASRuntimeExtensions.m */; }; + 87CD2EF61C8722020096516D /* NSDictionary+KeyValues.h in Headers */ = {isa = PBXBuildFile; fileRef = 87CD2EF41C8722020096516D /* NSDictionary+KeyValues.h */; }; + 87CD2EF71C8722020096516D /* NSDictionary+KeyValues.m in Sources */ = {isa = PBXBuildFile; fileRef = 87CD2EF51C8722020096516D /* NSDictionary+KeyValues.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -160,6 +162,8 @@ 1EC719AA1B67AF9C00700A14 /* CASPropertyDescriptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CASPropertyDescriptor.m; sourceTree = ""; }; 1EC719AB1B67AF9C00700A14 /* CASRuntimeExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CASRuntimeExtensions.h; sourceTree = ""; }; 1EC719AC1B67AF9C00700A14 /* CASRuntimeExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CASRuntimeExtensions.m; sourceTree = ""; }; + 87CD2EF41C8722020096516D /* NSDictionary+KeyValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+KeyValues.h"; sourceTree = ""; }; + 87CD2EF51C8722020096516D /* NSDictionary+KeyValues.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+KeyValues.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -243,6 +247,8 @@ 1EC7197C1B67AF9C00700A14 /* UIView+CASAdditions.m */, 1EC7197D1B67AF9C00700A14 /* UIViewController+CASAdditions.h */, 1EC7197E1B67AF9C00700A14 /* UIViewController+CASAdditions.m */, + 87CD2EF41C8722020096516D /* NSDictionary+KeyValues.h */, + 87CD2EF51C8722020096516D /* NSDictionary+KeyValues.m */, ); name = Additions; path = Classy/Additions; @@ -317,6 +323,7 @@ 1EC719CB1B67AF9C00700A14 /* Classy.h in Headers */, 1EC719B91B67AF9C00700A14 /* UIColor+CASAdditions.h in Headers */, 1EC719F31B67AF9C00700A14 /* CASPropertyDescriptor.h in Headers */, + 87CD2EF61C8722020096516D /* NSDictionary+KeyValues.h in Headers */, 1EC719ED1B67AF9C00700A14 /* CASArgumentDescriptor.h in Headers */, 1EC719F11B67AF9C00700A14 /* CASObjectClassDescriptor.h in Headers */, 1EC719EB1B67AF9C00700A14 /* CASUtilities.h in Headers */, @@ -463,6 +470,7 @@ 1EC719BE1B67AF9C00700A14 /* UINavigationItem+CASAdditions.m in Sources */, 1EC719D81B67AF9C00700A14 /* CASInvocation.m in Sources */, 1EC719E61B67AF9C00700A14 /* CASTextAttributes.m in Sources */, + 87CD2EF71C8722020096516D /* NSDictionary+KeyValues.m in Sources */, 1EC719C41B67AF9C00700A14 /* UITextField+CASAdditions.m in Sources */, 1EC719B61B67AF9C00700A14 /* NSString+CASAdditions.m in Sources */, 1EC719F41B67AF9C00700A14 /* CASPropertyDescriptor.m in Sources */, diff --git a/Classy/Additions/NSDictionary+KeyValues.h b/Classy/Additions/NSDictionary+KeyValues.h new file mode 100644 index 0000000..230c519 --- /dev/null +++ b/Classy/Additions/NSDictionary+KeyValues.h @@ -0,0 +1,14 @@ +// +// NSDictionary+KeyValues.h +// Classy +// +// Created by Mihail Gerasimenko on 3/2/16. +// Copyright © 2016 Zeta Project Berlin Gmbh. All rights reserved. +// + +#import + +@interface NSDictionary (CASKeyValues) +- (NSArray *)cas_keyValues; +- (NSArray *)cas_sortedKeyValues; +@end diff --git a/Classy/Additions/NSDictionary+KeyValues.m b/Classy/Additions/NSDictionary+KeyValues.m new file mode 100644 index 0000000..59906fb --- /dev/null +++ b/Classy/Additions/NSDictionary+KeyValues.m @@ -0,0 +1,30 @@ +// +// NSDictionary+KeyValues.m +// Classy +// +// Created by Mihail Gerasimenko on 3/2/16. +// Copyright © 2016 Zeta Project Berlin Gmbh. All rights reserved. +// + +#import "NSDictionary+KeyValues.h" + +@implementation NSDictionary (CASKeyValues) + +- (NSArray *)cas_keyValues +{ + NSArray *allKeys = self.allKeys; + NSMutableArray *result = [NSMutableArray arrayWithCapacity:allKeys.count]; + for (NSString *key in allKeys) { + NSDictionary *keyValue = [NSDictionary dictionaryWithObjectsAndKeys:key, @"key", [self objectForKey:key], @"value", nil]; + [result addObject:keyValue]; + } + return [result copy]; +} + +- (NSArray *)cas_sortedKeyValues +{ + NSSortDescriptor *sortByKey = [[NSSortDescriptor alloc] initWithKey:@"key" ascending:YES]; + return [self.cas_keyValues sortedArrayUsingDescriptors:@[sortByKey]]; +} + +@end diff --git a/Classy/Classy.h b/Classy/Classy.h index a745090..0b3141f 100644 --- a/Classy/Classy.h +++ b/Classy/Classy.h @@ -22,3 +22,5 @@ #import "UINavigationBar+CASAdditions.h" #import "UITabBar+CASAdditions.h" #import "UIToolbar+CASAdditions.h" +#import "UIViewController+CASAdditions.h" +#import "UINavigationItem+CASAdditions.h" diff --git a/Classy/Parser/CASStyler.m b/Classy/Parser/CASStyler.m index c217e03..2ea0158 100644 --- a/Classy/Parser/CASStyler.m +++ b/Classy/Parser/CASStyler.m @@ -17,6 +17,7 @@ #import "NSString+CASAdditions.h" #import "CASTextAttributes.h" #import "CASInvocation.h" +#import "NSDictionary+KeyValues.h" #import "UIBarItem+CASAdditions.h" #import "UINavigationItem+CASAdditions.h" @@ -182,23 +183,47 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { NSSet *importedFileNames = nil; NSMutableData *fileData = [NSMutableData dataWithContentsOfFile:filePath]; - [fileData appendData:[NSKeyedArchiver archivedDataWithRootObject:self.variables]]; - NSString *casHash = [fileData generateMD5Hash]; + NSError *jsonWriteError = nil; + NSArray *preprocessedVariables = self.variables.cas_sortedKeyValues; + NSData *variablesJSON = [NSJSONSerialization dataWithJSONObject:preprocessedVariables + options:NSJSONWritingPrettyPrinted + error:&jsonWriteError]; - NSArray* cachePathArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - NSString* cachePath = [cachePathArray lastObject]; - NSString *bcasPath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-%@.bcas", [[filePath lastPathComponent] stringByDeletingPathExtension], casHash]]; + BOOL bcasCanBeLoaded = NO; + NSString *bcasPath = nil; - NSError *fileSystemError = nil; - - NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:bcasPath error:nil]; - - if ([[NSFileManager defaultManager] fileExistsAtPath:bcasPath] && [fileAttributes[NSFileSize] integerValue] != 0) { + if (jsonWriteError == nil && variablesJSON != nil) { + [fileData appendData:variablesJSON]; + NSString *casHash = [fileData generateMD5Hash]; + + NSArray* cachePathArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString* cachePath = [cachePathArray lastObject]; + bcasPath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-%@.bcas", [[filePath lastPathComponent] stringByDeletingPathExtension], casHash]]; + + NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:bcasPath error:nil]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:bcasPath] && [fileAttributes[NSFileSize] integerValue] != 0) { + bcasCanBeLoaded = YES; + CASLog(@"Loading bcas file"); + } + else { + bcasCanBeLoaded = NO; + CASLog(@"bcas file not found"); + } + } + else { + bcasCanBeLoaded = NO; + CASLog(@"Cannot create json from variables: %@", jsonWriteError); + } + + if (bcasCanBeLoaded) { styleNodes = [NSKeyedUnarchiver unarchiveObjectWithFile:bcasPath]; importedFileNames = [NSSet set]; } else { + NSError *fileSystemError = nil; + CASParser *parser = [CASParser parserFromFilePath:filePath variables:self.variables error:error]; styleNodes = parser.styleNodes; importedFileNames = parser.importedFileNames; @@ -211,10 +236,11 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { error:&fileSystemError]; if (fileSystemError != nil) { - NSLog(@"Error: cannot create folder %@", [bcasPath stringByDeletingLastPathComponent]); + CASLog(@"Error: cannot create folder %@", [bcasPath stringByDeletingLastPathComponent]); fileSystemError = nil; } [data writeToFile:bcasPath atomically:YES]; + CASLog(@"Caching to bcas: %@ (%u)", bcasPath, (unsigned int)data.length); } if (self.watchFilePath) { diff --git a/Classy/Parser/CASUtilities.h b/Classy/Parser/CASUtilities.h index 3bb4fad..c598662 100644 --- a/Classy/Parser/CASUtilities.h +++ b/Classy/Parser/CASUtilities.h @@ -35,4 +35,4 @@ BOOL CASDeviceSystemVersionIsGreaterThanOrEqualTo(NSString *systemVersion); BOOL CASDeviceSystemVersionIsLessThan(NSString *systemVersion); -BOOL CASDeviceSystemVersionIsLessThanOrEqualTo(NSString *systemVersion); \ No newline at end of file +BOOL CASDeviceSystemVersionIsLessThanOrEqualTo(NSString *systemVersion); From e4ac454df0a14f63e3da05e312e7716bb1951bf5 Mon Sep 17 00:00:00 2001 From: Gerasimenko Mike Date: Mon, 7 Mar 2016 12:32:39 +0100 Subject: [PATCH 13/15] Moved classy encoding to client code --- Classy.xcodeproj/project.pbxproj | 8 -- Classy/Additions/NSDictionary+KeyValues.h | 14 --- Classy/Additions/NSDictionary+KeyValues.m | 30 ------ Classy/Parser/CASDeviceScreenSizeItem.h | 2 +- Classy/Parser/CASStyleProperty.h | 2 +- Classy/Parser/CASStyler.h | 9 ++ Classy/Parser/CASStyler.m | 108 +++++----------------- Classy/Parser/CASToken.m | 2 - 8 files changed, 33 insertions(+), 142 deletions(-) delete mode 100644 Classy/Additions/NSDictionary+KeyValues.h delete mode 100644 Classy/Additions/NSDictionary+KeyValues.m diff --git a/Classy.xcodeproj/project.pbxproj b/Classy.xcodeproj/project.pbxproj index 888566f..8d9fb20 100644 --- a/Classy.xcodeproj/project.pbxproj +++ b/Classy.xcodeproj/project.pbxproj @@ -81,8 +81,6 @@ 1EC719F41B67AF9C00700A14 /* CASPropertyDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EC719AA1B67AF9C00700A14 /* CASPropertyDescriptor.m */; }; 1EC719F51B67AF9C00700A14 /* CASRuntimeExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC719AB1B67AF9C00700A14 /* CASRuntimeExtensions.h */; }; 1EC719F61B67AF9C00700A14 /* CASRuntimeExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EC719AC1B67AF9C00700A14 /* CASRuntimeExtensions.m */; }; - 87CD2EF61C8722020096516D /* NSDictionary+KeyValues.h in Headers */ = {isa = PBXBuildFile; fileRef = 87CD2EF41C8722020096516D /* NSDictionary+KeyValues.h */; }; - 87CD2EF71C8722020096516D /* NSDictionary+KeyValues.m in Sources */ = {isa = PBXBuildFile; fileRef = 87CD2EF51C8722020096516D /* NSDictionary+KeyValues.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -162,8 +160,6 @@ 1EC719AA1B67AF9C00700A14 /* CASPropertyDescriptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CASPropertyDescriptor.m; sourceTree = ""; }; 1EC719AB1B67AF9C00700A14 /* CASRuntimeExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CASRuntimeExtensions.h; sourceTree = ""; }; 1EC719AC1B67AF9C00700A14 /* CASRuntimeExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CASRuntimeExtensions.m; sourceTree = ""; }; - 87CD2EF41C8722020096516D /* NSDictionary+KeyValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+KeyValues.h"; sourceTree = ""; }; - 87CD2EF51C8722020096516D /* NSDictionary+KeyValues.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+KeyValues.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -247,8 +243,6 @@ 1EC7197C1B67AF9C00700A14 /* UIView+CASAdditions.m */, 1EC7197D1B67AF9C00700A14 /* UIViewController+CASAdditions.h */, 1EC7197E1B67AF9C00700A14 /* UIViewController+CASAdditions.m */, - 87CD2EF41C8722020096516D /* NSDictionary+KeyValues.h */, - 87CD2EF51C8722020096516D /* NSDictionary+KeyValues.m */, ); name = Additions; path = Classy/Additions; @@ -323,7 +317,6 @@ 1EC719CB1B67AF9C00700A14 /* Classy.h in Headers */, 1EC719B91B67AF9C00700A14 /* UIColor+CASAdditions.h in Headers */, 1EC719F31B67AF9C00700A14 /* CASPropertyDescriptor.h in Headers */, - 87CD2EF61C8722020096516D /* NSDictionary+KeyValues.h in Headers */, 1EC719ED1B67AF9C00700A14 /* CASArgumentDescriptor.h in Headers */, 1EC719F11B67AF9C00700A14 /* CASObjectClassDescriptor.h in Headers */, 1EC719EB1B67AF9C00700A14 /* CASUtilities.h in Headers */, @@ -470,7 +463,6 @@ 1EC719BE1B67AF9C00700A14 /* UINavigationItem+CASAdditions.m in Sources */, 1EC719D81B67AF9C00700A14 /* CASInvocation.m in Sources */, 1EC719E61B67AF9C00700A14 /* CASTextAttributes.m in Sources */, - 87CD2EF71C8722020096516D /* NSDictionary+KeyValues.m in Sources */, 1EC719C41B67AF9C00700A14 /* UITextField+CASAdditions.m in Sources */, 1EC719B61B67AF9C00700A14 /* NSString+CASAdditions.m in Sources */, 1EC719F41B67AF9C00700A14 /* CASPropertyDescriptor.m in Sources */, diff --git a/Classy/Additions/NSDictionary+KeyValues.h b/Classy/Additions/NSDictionary+KeyValues.h deleted file mode 100644 index 230c519..0000000 --- a/Classy/Additions/NSDictionary+KeyValues.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// NSDictionary+KeyValues.h -// Classy -// -// Created by Mihail Gerasimenko on 3/2/16. -// Copyright © 2016 Zeta Project Berlin Gmbh. All rights reserved. -// - -#import - -@interface NSDictionary (CASKeyValues) -- (NSArray *)cas_keyValues; -- (NSArray *)cas_sortedKeyValues; -@end diff --git a/Classy/Additions/NSDictionary+KeyValues.m b/Classy/Additions/NSDictionary+KeyValues.m deleted file mode 100644 index 59906fb..0000000 --- a/Classy/Additions/NSDictionary+KeyValues.m +++ /dev/null @@ -1,30 +0,0 @@ -// -// NSDictionary+KeyValues.m -// Classy -// -// Created by Mihail Gerasimenko on 3/2/16. -// Copyright © 2016 Zeta Project Berlin Gmbh. All rights reserved. -// - -#import "NSDictionary+KeyValues.h" - -@implementation NSDictionary (CASKeyValues) - -- (NSArray *)cas_keyValues -{ - NSArray *allKeys = self.allKeys; - NSMutableArray *result = [NSMutableArray arrayWithCapacity:allKeys.count]; - for (NSString *key in allKeys) { - NSDictionary *keyValue = [NSDictionary dictionaryWithObjectsAndKeys:key, @"key", [self objectForKey:key], @"value", nil]; - [result addObject:keyValue]; - } - return [result copy]; -} - -- (NSArray *)cas_sortedKeyValues -{ - NSSortDescriptor *sortByKey = [[NSSortDescriptor alloc] initWithKey:@"key" ascending:YES]; - return [self.cas_keyValues sortedArrayUsingDescriptors:@[sortByKey]]; -} - -@end diff --git a/Classy/Parser/CASDeviceScreenSizeItem.h b/Classy/Parser/CASDeviceScreenSizeItem.h index 36c2d0d..7c635e6 100644 --- a/Classy/Parser/CASDeviceScreenSizeItem.h +++ b/Classy/Parser/CASDeviceScreenSizeItem.h @@ -14,4 +14,4 @@ @property (nonatomic, assign) CASRelation relation; @property(nonatomic, assign) CASDeviceSelectorScreenDimension dimension; -@end \ No newline at end of file +@end diff --git a/Classy/Parser/CASStyleProperty.h b/Classy/Parser/CASStyleProperty.h index 59ba336..08c6fa0 100644 --- a/Classy/Parser/CASStyleProperty.h +++ b/Classy/Parser/CASStyleProperty.h @@ -44,7 +44,7 @@ @property (nonatomic, strong) NSDictionary *arguments; /** - * Creates property with raw data in the form of CATokens + * Creates property with raw data in the form of CASTokens */ - (id)initWithNameToken:(CASToken *)nameToken valueTokens:(NSArray *)valueTokens; diff --git a/Classy/Parser/CASStyler.h b/Classy/Parser/CASStyler.h index 5cc9149..5ffd018 100644 --- a/Classy/Parser/CASStyler.h +++ b/Classy/Parser/CASStyler.h @@ -10,6 +10,13 @@ #import "CASObjectClassDescriptor.h" #import "CASStyleableItem.h" +@protocol CASStylerCacheDelegate +@optional +- (NSArray *)cachedStyleNodesFromPath:(NSString *)path withVariables:(NSDictionary *)variables; +- (void)cacheStyleNodes:(NSArray *)styleNodes fromPath:(NSString *)path variables:(NSDictionary *)variables; +@end + + @interface CASStyler : NSObject + (void)bootstrapClassyWithTargetWindows:(NSArray *)targetWindows; @@ -19,6 +26,8 @@ */ + (instancetype)defaultStyler; +@property (nonatomic, weak) id cacheDelegate; + @property (nonatomic, copy) NSDictionary *variables; /** diff --git a/Classy/Parser/CASStyler.m b/Classy/Parser/CASStyler.m index 2ea0158..9c26510 100644 --- a/Classy/Parser/CASStyler.m +++ b/Classy/Parser/CASStyler.m @@ -17,7 +17,6 @@ #import "NSString+CASAdditions.h" #import "CASTextAttributes.h" #import "CASInvocation.h" -#import "NSDictionary+KeyValues.h" #import "UIBarItem+CASAdditions.h" #import "UINavigationItem+CASAdditions.h" @@ -25,7 +24,6 @@ #import "UIView+CASAdditions.h" #import "UIViewController+CASAdditions.h" #import -#import // http://www.cocoawithlove.com/2010/01/getting-subclasses-of-objective-c-class.html NSArray *ClassGetSubclasses(Class parentClass) { @@ -51,26 +49,6 @@ return result; } -@interface NSData(MD5) - -- (NSString *)generateMD5Hash; - -@end - -@implementation NSData(MD5) - -- (NSString *)generateMD5Hash -{ - unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH]; - CC_MD5(self.bytes, (CC_LONG)self.length, md5Buffer); - NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; - for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) - [output appendFormat:@"%02x",md5Buffer[i]]; - - return output; -} - -@end @interface CASStyler () @@ -182,67 +160,40 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { NSArray *styleNodes = nil; NSSet *importedFileNames = nil; - NSMutableData *fileData = [NSMutableData dataWithContentsOfFile:filePath]; - - NSError *jsonWriteError = nil; - NSArray *preprocessedVariables = self.variables.cas_sortedKeyValues; - NSData *variablesJSON = [NSJSONSerialization dataWithJSONObject:preprocessedVariables - options:NSJSONWritingPrettyPrinted - error:&jsonWriteError]; - - BOOL bcasCanBeLoaded = NO; - NSString *bcasPath = nil; - - if (jsonWriteError == nil && variablesJSON != nil) { - [fileData appendData:variablesJSON]; - NSString *casHash = [fileData generateMD5Hash]; - - NSArray* cachePathArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - NSString* cachePath = [cachePathArray lastObject]; - bcasPath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-%@.bcas", [[filePath lastPathComponent] stringByDeletingPathExtension], casHash]]; - - NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:bcasPath error:nil]; - - if ([[NSFileManager defaultManager] fileExistsAtPath:bcasPath] && [fileAttributes[NSFileSize] integerValue] != 0) { - bcasCanBeLoaded = YES; - CASLog(@"Loading bcas file"); - } - else { - bcasCanBeLoaded = NO; - CASLog(@"bcas file not found"); - } - } - else { - bcasCanBeLoaded = NO; - CASLog(@"Cannot create json from variables: %@", jsonWriteError); + if ([self.cacheDelegate respondsToSelector:@selector(cachedStyleNodesFromPath:withVariables:)]) { + styleNodes = [self.cacheDelegate cachedStyleNodesFromPath:filePath withVariables:self.variables]; } - - if (bcasCanBeLoaded) { - styleNodes = [NSKeyedUnarchiver unarchiveObjectWithFile:bcasPath]; + + if (styleNodes != nil) { importedFileNames = [NSSet set]; + self.styleNodes = [NSMutableArray arrayWithArray:styleNodes]; } else { - NSError *fileSystemError = nil; - CASParser *parser = [CASParser parserFromFilePath:filePath variables:self.variables error:error]; styleNodes = parser.styleNodes; importedFileNames = parser.importedFileNames; - NSData *data = [NSKeyedArchiver archivedDataWithRootObject:parser.styleNodes]; + self.styleNodes = [self validNodes:styleNodes]; + + // order ascending by precedence + [self.styleNodes sortWithOptions:NSSortStable usingComparator:^NSComparisonResult(CASStyleNode *n1, CASStyleNode *n2) { + NSInteger precedence1 = [n1.styleSelector precedence]; + NSInteger precedence2 = [n2.styleSelector precedence]; + if (precedence2 > precedence1) { + return NSOrderedAscending; + } else if (precedence2 < precedence1) { + return NSOrderedDescending; + } + return NSOrderedSame; + }]; - [[NSFileManager defaultManager] createDirectoryAtPath:[bcasPath stringByDeletingLastPathComponent] - withIntermediateDirectories:YES - attributes:nil - error:&fileSystemError]; - if (fileSystemError != nil) { - CASLog(@"Error: cannot create folder %@", [bcasPath stringByDeletingLastPathComponent]); - fileSystemError = nil; + if ([self.cacheDelegate respondsToSelector:@selector(cacheStyleNodes:fromPath:variables:)]) { + [self.cacheDelegate cacheStyleNodes:styleNodes fromPath:filePath variables:self.variables]; } - [data writeToFile:bcasPath atomically:YES]; - CASLog(@"Caching to bcas: %@ (%u)", bcasPath, (unsigned int)data.length); + styleNodes = [self.cacheDelegate cachedStyleNodesFromPath:filePath withVariables:self.variables]; } - + if (self.watchFilePath) { for (dispatch_source_t source in self.fileWatchers) { dispatch_source_cancel(source); @@ -256,25 +207,10 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { } } - if (!styleNodes.count) { return; } - self.styleNodes = [self validNodes:styleNodes]; - - // order ascending by precedence - [self.styleNodes sortWithOptions:NSSortStable usingComparator:^NSComparisonResult(CASStyleNode *n1, CASStyleNode *n2) { - NSInteger precedence1 = [n1.styleSelector precedence]; - NSInteger precedence2 = [n2.styleSelector precedence]; - if (precedence2 > precedence1) { - return NSOrderedAscending; - } else if (precedence2 < precedence1) { - return NSOrderedDescending; - } - return NSOrderedSame; - }]; - [self populateStyleLookupTables:self.styleNodes]; self.invocationObjectArguments = NSMutableArray.new; diff --git a/Classy/Parser/CASToken.m b/Classy/Parser/CASToken.m index b0c2c2b..aa7db1f 100644 --- a/Classy/Parser/CASToken.m +++ b/Classy/Parser/CASToken.m @@ -158,7 +158,6 @@ - (id)initWithCoder:(NSCoder *)aDecoder { if (self != nil) { self.type = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(type))]; self.value = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(value))]; - self.lineNumber = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(lineNumber))]; } return self; @@ -167,7 +166,6 @@ - (id)initWithCoder:(NSCoder *)aDecoder { - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeInteger:self.type forKey:NSStringFromSelector(@selector(type))]; [aCoder encodeObject:self.value forKey:NSStringFromSelector(@selector(value))]; - [aCoder encodeInteger:self.lineNumber forKey:NSStringFromSelector(@selector(lineNumber))]; } @end From a12b9ad4a7d6aa8abf3ada3e162177eb2e5fe8aa Mon Sep 17 00:00:00 2001 From: Gerasimenko Mike Date: Mon, 7 Mar 2016 13:47:14 +0100 Subject: [PATCH 14/15] Cleanup --- Classy/Parser/CASToken.m | 2 +- .../ClassyExample.xcodeproj/project.pbxproj | 20 +++++-------------- Example/ClassyExample/CASAppDelegate.m | 4 +--- .../ClassyExample/Stylesheets/stylesheet.cas | 2 +- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/Classy/Parser/CASToken.m b/Classy/Parser/CASToken.m index aa7db1f..0ea0b08 100644 --- a/Classy/Parser/CASToken.m +++ b/Classy/Parser/CASToken.m @@ -144,7 +144,7 @@ - (BOOL)isEqual:(id)object if ([object isKindOfClass:[CASToken class]]) { CASToken *other = object; - return other.type == self.type && ([other.value isEqual:self.value] || other.value == self.value) && other.lineNumber == self.lineNumber; + return other.type == self.type && ([other.value isEqual:self.value] || other.value == self.value); } else { return NO; diff --git a/Example/ClassyExample.xcodeproj/project.pbxproj b/Example/ClassyExample.xcodeproj/project.pbxproj index a921767..cc22a16 100644 --- a/Example/ClassyExample.xcodeproj/project.pbxproj +++ b/Example/ClassyExample.xcodeproj/project.pbxproj @@ -24,9 +24,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 136384E66419452BA007511C /* Pods-ClassyExample.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyExample.xcconfig"; path = "../Pods/Pods-ClassyExample.xcconfig"; sourceTree = ""; }; 4E506421190EF2F8003A03B0 /* Ball.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Ball.png; sourceTree = ""; }; - A3C8221728799761B99AE9BD /* Pods-ClassyExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyExample.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-ClassyExample/Pods-ClassyExample.debug.xcconfig"; sourceTree = ""; }; - BB716E9DB58A99D4756CD771 /* Pods-ClassyExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClassyExample.release.xcconfig"; path = "../Pods/Target Support Files/Pods-ClassyExample/Pods-ClassyExample.release.xcconfig"; sourceTree = ""; }; DD355BDA183E9CD30071E543 /* variables.cas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = variables.cas; sourceTree = ""; }; DD61F4431816370F004A8777 /* stylesheet.cas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = stylesheet.cas; sourceTree = ""; }; DDAB25671814BBBB00F3DAAE /* ClassyExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ClassyExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -73,15 +72,6 @@ name = Images; sourceTree = ""; }; - B100602FAA9CDE99D59C2194 /* Pods */ = { - isa = PBXGroup; - children = ( - A3C8221728799761B99AE9BD /* Pods-ClassyExample.debug.xcconfig */, - BB716E9DB58A99D4756CD771 /* Pods-ClassyExample.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; DD61F4421816370F004A8777 /* Stylesheets */ = { isa = PBXGroup; children = ( @@ -97,7 +87,7 @@ DDAB25701814BBBB00F3DAAE /* ClassyExample */, DDAB25691814BBBB00F3DAAE /* Frameworks */, DDAB25681814BBBB00F3DAAE /* Products */, - B100602FAA9CDE99D59C2194 /* Pods */, + 136384E66419452BA007511C /* Pods-ClassyExample.xcconfig */, ); sourceTree = ""; }; @@ -228,7 +218,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/../Pods/Target Support Files/Pods-ClassyExample/Pods-ClassyExample-resources.sh\"\n"; + shellScript = "\"${SRCROOT}/../Pods/Pods-ClassyExample-resources.sh\"\n"; showEnvVarsInLog = 0; }; 501B6904610449669F2F8026 /* Check Pods Manifest.lock */ = { @@ -351,7 +341,7 @@ }; DDAB25941814BBBB00F3DAAE /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A3C8221728799761B99AE9BD /* Pods-ClassyExample.debug.xcconfig */; + baseConfigurationReference = 136384E66419452BA007511C /* Pods-ClassyExample.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; @@ -366,7 +356,7 @@ }; DDAB25951814BBBB00F3DAAE /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = BB716E9DB58A99D4756CD771 /* Pods-ClassyExample.release.xcconfig */; + baseConfigurationReference = 136384E66419452BA007511C /* Pods-ClassyExample.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; diff --git a/Example/ClassyExample/CASAppDelegate.m b/Example/ClassyExample/CASAppDelegate.m index 6a41a96..e00fcd5 100644 --- a/Example/ClassyExample/CASAppDelegate.m +++ b/Example/ClassyExample/CASAppDelegate.m @@ -13,9 +13,7 @@ @implementation CASAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [CASStyler bootstrapClassy]; - - [[CASStyler defaultStyler] setVariables:@{@"$accent": @"#ff0000"}]; + #if TARGET_IPHONE_SIMULATOR // get absolute file path of stylesheet, using relative path diff --git a/Example/ClassyExample/Stylesheets/stylesheet.cas b/Example/ClassyExample/Stylesheets/stylesheet.cas index 189bc94..df112c0 100644 --- a/Example/ClassyExample/Stylesheets/stylesheet.cas +++ b/Example/ClassyExample/Stylesheets/stylesheet.cas @@ -6,7 +6,7 @@ UITableView UILabel { } ^UIViewController > UIView { - background-color: $accent; + background-color: blue; } UIView.shadow-view { From e0b762717f6ce12f4ae907bf9203a2b85e1e7f1d Mon Sep 17 00:00:00 2001 From: Gerasimenko Mike Date: Wed, 9 Mar 2016 15:17:38 +0100 Subject: [PATCH 15/15] Added comments and cleaned up --- Classy/Parser/CASStyler.h | 21 +++++++++++++++++---- Classy/Parser/CASStyler.m | 10 ++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Classy/Parser/CASStyler.h b/Classy/Parser/CASStyler.h index 5ffd018..c3df1f6 100644 --- a/Classy/Parser/CASStyler.h +++ b/Classy/Parser/CASStyler.h @@ -10,10 +10,23 @@ #import "CASObjectClassDescriptor.h" #import "CASStyleableItem.h" -@protocol CASStylerCacheDelegate +@class CASStyleNode; + +/** + * Protocol caching the @c CASStyleNode's. Adds the possibility to cache the in-memory representation of Classy's CAS + * file, since parsing the file is slower than loading cached version. + */ +@protocol CASCacheProtocol @optional -- (NSArray *)cachedStyleNodesFromPath:(NSString *)path withVariables:(NSDictionary *)variables; -- (void)cacheStyleNodes:(NSArray *)styleNodes fromPath:(NSString *)path variables:(NSDictionary *)variables; +/** + * Loads cached version of stylesheet located at @c path with @c variables + */ +- (NSArray *)cachedStyleNodesFromCASPath:(NSString *)path withVariables:(NSDictionary *)variables; + +/** + * Stores the stylesheet in-memory representation loaded from @c path with @c variables + */ +- (void)cacheStyleNodes:(NSArray *)styleNodes fromPath:(NSString *)path variables:(NSDictionary *)variables; @end @@ -26,7 +39,7 @@ */ + (instancetype)defaultStyler; -@property (nonatomic, weak) id cacheDelegate; +@property (nonatomic, weak) id cache; @property (nonatomic, copy) NSDictionary *variables; diff --git a/Classy/Parser/CASStyler.m b/Classy/Parser/CASStyler.m index 9c26510..7bca5d9 100644 --- a/Classy/Parser/CASStyler.m +++ b/Classy/Parser/CASStyler.m @@ -160,8 +160,8 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { NSArray *styleNodes = nil; NSSet *importedFileNames = nil; - if ([self.cacheDelegate respondsToSelector:@selector(cachedStyleNodesFromPath:withVariables:)]) { - styleNodes = [self.cacheDelegate cachedStyleNodesFromPath:filePath withVariables:self.variables]; + if ([self.cache respondsToSelector:@selector(cachedStyleNodesFromCASPath:withVariables:)]) { + styleNodes = [self.cache cachedStyleNodesFromCASPath:filePath withVariables:self.variables]; } if (styleNodes != nil) { @@ -186,12 +186,10 @@ - (void)setFilePath:(NSString *)filePath error:(NSError **)error { } return NSOrderedSame; }]; - - if ([self.cacheDelegate respondsToSelector:@selector(cacheStyleNodes:fromPath:variables:)]) { - [self.cacheDelegate cacheStyleNodes:styleNodes fromPath:filePath variables:self.variables]; + if ([self.cache respondsToSelector:@selector(cacheStyleNodes:fromPath:variables:)]) { + [self.cache cacheStyleNodes:styleNodes fromPath:filePath variables:self.variables]; } - styleNodes = [self.cacheDelegate cachedStyleNodesFromPath:filePath withVariables:self.variables]; } if (self.watchFilePath) {