Permalink
Browse files

Support for Dates, Fix bug in offset computation for webviews

  • Loading branch information...
1 parent e067804 commit 2f00a23ff83cc801ad7bcfc49a1e7c4d59c65671 @krukow krukow committed Oct 11, 2012
View
@@ -0,0 +1,9 @@
+Copyright © 2006–2011 Peter Hosey
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+Neither the name of Peter Hosey nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -24,6 +24,8 @@
/* Begin PBXBuildFile section */
B1296FC015DC1F4B005DDF5C /* LPReflectUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = B1296FBF15DC1F4B005DDF5C /* LPReflectUtils.h */; };
B1296FC315DC1F5B005DDF5C /* LPReflectUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B1296FC215DC1F5B005DDF5C /* LPReflectUtils.m */; };
+ B13B29251627389500433F6C /* LPISO8601DateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = B13B29231627389500433F6C /* LPISO8601DateFormatter.h */; };
+ B13B29261627389500433F6C /* LPISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = B13B29241627389500433F6C /* LPISO8601DateFormatter.m */; };
B13D5F8A15D43A3900504726 /* LPI.mm in Sources */ = {isa = PBXBuildFile; fileRef = B184FDBD14B6DB2B002A744C /* LPI.mm */; };
B17E756E15D433A40066550B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B121E79714B6D9FB0034C6A9 /* Foundation.framework */; };
B17E757B15D434D00066550B /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B17E757A15D434D00066550B /* CFNetwork.framework */; };
@@ -144,6 +146,8 @@
B1296FC215DC1F5B005DDF5C /* LPReflectUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LPReflectUtils.m; sourceTree = "<group>"; };
B12A04001511546F002FA032 /* LPInterpolateRoute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LPInterpolateRoute.h; sourceTree = "<group>"; };
B12A04011511546F002FA032 /* LPInterpolateRoute.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LPInterpolateRoute.m; sourceTree = "<group>"; };
+ B13B29231627389500433F6C /* LPISO8601DateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LPISO8601DateFormatter.h; sourceTree = "<group>"; };
+ B13B29241627389500433F6C /* LPISO8601DateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LPISO8601DateFormatter.m; sourceTree = "<group>"; };
B153F55A15949F3D00867E12 /* LPVersionRoute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LPVersionRoute.h; sourceTree = "<group>"; };
B153F55B15949F3D00867E12 /* LPVersionRoute.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LPVersionRoute.m; sourceTree = "<group>"; };
B15DA5E315C5D80A009E6CFE /* LPQueryAllOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LPQueryAllOperation.h; sourceTree = "<group>"; };
@@ -497,6 +501,8 @@
B184FDDD14B6DB2B002A744C /* JSON */ = {
isa = PBXGroup;
children = (
+ B13B29231627389500433F6C /* LPISO8601DateFormatter.h */,
+ B13B29241627389500433F6C /* LPISO8601DateFormatter.m */,
B184FDDE14B6DB2B002A744C /* CDataScanner_Extensions.h */,
B184FDDF14B6DB2B002A744C /* CDataScanner_Extensions.m */,
B184FDE014B6DB2B002A744C /* LPCJSONDeserializer.h */,
@@ -599,6 +605,7 @@
files = (
B17E75B615D436100066550B /* CalabashServer.h in Headers */,
B1296FC015DC1F4B005DDF5C /* LPReflectUtils.h in Headers */,
+ B13B29251627389500433F6C /* LPISO8601DateFormatter.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -678,7 +685,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "set -e\nset +u\n# Avoid recursively calling this script.\nif [[ $SF_MASTER_SCRIPT_RUNNING ]]\nthen\nexit 0\nfi\nset -u\nexport SF_MASTER_SCRIPT_RUNNING=1\n\nSF_TARGET_NAME=${PROJECT_NAME}\nSF_EXECUTABLE_PATH=\"lib${SF_TARGET_NAME}.a\"\nSF_WRAPPER_NAME=\"${SF_TARGET_NAME}.framework\"\n\n# The following conditionals come from\n# https://github.com/kstenerud/iOS-Universal-Framework\n\nif [[ \"$SDK_NAME\" =~ ([A-Za-z]+) ]]\nthen\nSF_SDK_PLATFORM=${BASH_REMATCH[1]}\nelse\necho \"Could not find platform name from SDK_NAME: $SDK_NAME\"\nexit 1\nfi\n\nif [[ \"$SDK_NAME\" =~ ([0-9]+.*$) ]]\nthen\nSF_SDK_VERSION=${BASH_REMATCH[1]}\nelse\necho \"Could not find sdk version from SDK_NAME: $SDK_NAME\"\nexit 1\nfi\n\nif [[ \"$SF_SDK_PLATFORM\" = \"iphoneos\" ]]\nthen\nSF_OTHER_PLATFORM=iphonesimulator\nelse\nSF_OTHER_PLATFORM=iphoneos\nfi\n\nif [[ \"$BUILT_PRODUCTS_DIR\" =~ (.*)$SF_SDK_PLATFORM$ ]]\nthen\nSF_OTHER_BUILT_PRODUCTS_DIR=\"${BASH_REMATCH[1]}${SF_OTHER_PLATFORM}\"\nelse\necho \"Could not find platform name from build products directory: $BUILT_PRODUCTS_DIR\"\nexit 1\nfi\n\n# Build the other platform.\nxcodebuild -project \"${PROJECT_FILE_PATH}\" -target \"${TARGET_NAME}\" -configuration \"${CONFIGURATION}\" -sdk ${SF_OTHER_PLATFORM}${SF_SDK_VERSION} BUILD_DIR=\"${BUILD_DIR}\" OBJROOT=\"${OBJROOT}\" BUILD_ROOT=\"${BUILD_ROOT}\" SYMROOT=\"${SYMROOT}\" $ACTION\n\n# Smash the two static libraries into one fat binary and store it in the .framework\nlipo -create \"${BUILT_PRODUCTS_DIR}/${SF_EXECUTABLE_PATH}\" \"${SF_OTHER_BUILT_PRODUCTS_DIR}/${SF_EXECUTABLE_PATH}\" -output \"${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/${FRAMEWORK_VERSION}/${SF_TARGET_NAME}\"\n\n# Copy the binary to the other architecture folder to have a complete framework in both.\ncp -a \"${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/${FRAMEWORK_VERSION}/${SF_TARGET_NAME}\" \"${SF_OTHER_BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/${FRAMEWORK_VERSION}/${SF_TARGET_NAME}\"";
+ shellScript = "set -e\nset +u\n# Avoid recursively calling this script.\nif [[ $SF_MASTER_SCRIPT_RUNNING ]]\nthen\nexit 0\nfi\nset -u\nexport SF_MASTER_SCRIPT_RUNNING=1\n\nSF_TARGET_NAME=${PROJECT_NAME}\nSF_EXECUTABLE_PATH=\"lib${SF_TARGET_NAME}.a\"\nSF_WRAPPER_NAME=\"${SF_TARGET_NAME}.framework\"\n\n# The following conditionals come from\n# https://github.com/kstenerud/iOS-Universal-Framework\n\nif [[ \"$SDK_NAME\" =~ ([A-Za-z]+) ]]\nthen\nSF_SDK_PLATFORM=${BASH_REMATCH[1]}\nelse\necho \"Could not find platform name from SDK_NAME: $SDK_NAME\"\nexit 1\nfi\n\nif [[ \"$SDK_NAME\" =~ ([0-9]+.*$) ]]\nthen\nSF_SDK_VERSION=${BASH_REMATCH[1]}\nelse\necho \"Could not find sdk version from SDK_NAME: $SDK_NAME\"\nexit 1\nfi\n\nif [[ \"$SF_SDK_PLATFORM\" = \"iphoneos\" ]]\nthen\nSF_OTHER_PLATFORM=iphonesimulator\nelse\nSF_OTHER_PLATFORM=iphoneos\nfi\n\nif [[ \"$BUILT_PRODUCTS_DIR\" =~ (.*)$SF_SDK_PLATFORM$ ]]\nthen\nSF_OTHER_BUILT_PRODUCTS_DIR=\"${BASH_REMATCH[1]}${SF_OTHER_PLATFORM}\"\nelse\necho \"Could not find platform name from build products directory: $BUILT_PRODUCTS_DIR\"\nexit 1\nfi\n\n# Build the other platform.\nxcodebuild -project \"${PROJECT_FILE_PATH}\" -target \"${TARGET_NAME}\" -configuration \"${CONFIGURATION}\" -sdk ${SF_OTHER_PLATFORM}${SF_SDK_VERSION} BUILD_DIR=\"${BUILD_DIR}\" OBJROOT=\"${OBJROOT}\" BUILD_ROOT=\"${BUILD_ROOT}\" SYMROOT=\"${SYMROOT}\" $ACTION\n\n# Smash the two static libraries into one fat binary and store it in the .framework\nlipo -create \"${BUILT_PRODUCTS_DIR}/${SF_EXECUTABLE_PATH}\" \"${SF_OTHER_BUILT_PRODUCTS_DIR}/${SF_EXECUTABLE_PATH}\" -output \"${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/${FRAMEWORK_VERSION}/${SF_TARGET_NAME}\"\n\n# Copy the binary to the other architecture folder to have a complete framework in both.\ncp -a \"${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/${FRAMEWORK_VERSION}/${SF_TARGET_NAME}\" \"${SF_OTHER_BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/${FRAMEWORK_VERSION}/${SF_TARGET_NAME}\"\n\n# Copy the binary as a libcalabashuni.a file\ncp -a \"${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/${FRAMEWORK_VERSION}/${SF_TARGET_NAME}\" \"${BUILT_PRODUCTS_DIR}/lib${SF_TARGET_NAME}uni.a\"\n\n# Copy the binary as a libcalabashuni.a file\ncp -a \"${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/${FRAMEWORK_VERSION}/${SF_TARGET_NAME}\" \"${SF_OTHER_BUILT_PRODUCTS_DIR}/lib${SF_TARGET_NAME}uni.a\"\n";
};
/* End PBXShellScriptBuildPhase section */
@@ -744,6 +751,7 @@
B17E75B215D4357F0066550B /* CalabashServer.m in Sources */,
B13D5F8A15D43A3900504726 /* LPI.mm in Sources */,
B1296FC315DC1F5B005DDF5C /* LPReflectUtils.m in Sources */,
+ B13B29261627389500433F6C /* LPISO8601DateFormatter.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -8,7 +8,7 @@
#import "LPVersionRoute.h"
-#define kLPCALABASHVERSION @"0.9.103"
+#define kLPCALABASHVERSION @"0.9.109"
@implementation LPVersionRoute
@@ -28,6 +28,7 @@
//
#import "LPCJSONScanner.h"
+#import "LPISO8601DateFormatter.h"
#import "CDataScanner_Extensions.h"
@@ -180,6 +181,10 @@ - (BOOL)scanJSONObject:(id *)outObject error:(NSError **)outError
case '\"':
case '\'':
theResult = [self scanJSONStringConstant:&theObject error:outError];
+ if (theResult && theObject && [theObject isKindOfClass:[NSString class]])
+ {
+ theObject = [self asDateOrString:theObject];
+ }
break;
case '0':
case '1':
@@ -213,13 +218,32 @@ - (BOOL)scanJSONObject:(id *)outObject error:(NSError **)outError
}
break;
}
+
if (outObject != NULL)
*outObject = theObject;
return(theResult);
}
+-(id)asDateOrString:(NSString*) str
+{
+ static LPISO8601DateFormatter *dateFormat = nil;
+ if (dateFormat == nil)
+ {
+ dateFormat = [[LPISO8601DateFormatter alloc] init];
+ dateFormat.parsesStrictly = YES;
+ }
+ NSRange range;
+ NSDate *date = [dateFormat dateFromString:str timeZone:nil range:&range];
+ if (range.location != NSNotFound)
+ {
+ return date;
+ }
+ return str;
+
+}
+
- (BOOL)scanJSONDictionary:(NSDictionary **)outDictionary error:(NSError **)outError
{
NSUInteger theScanLocation = [self scanLocation];
@@ -28,6 +28,7 @@
//
#import "LPCJSONSerializer.h"
+#import "LPISO8601DateFormatter.h"
#import "LPJSONRepresentation.h"
@@ -124,6 +125,26 @@ - (NSData *)serializeObject:(id)inObject error:(NSError **)outError
NSString *theString = [[[NSString alloc] initWithData:inObject encoding:NSUTF8StringEncoding] autorelease];
theResult = [self serializeString:theString error:outError];
}
+ else if ([inObject isKindOfClass:[NSDate class]])
+ {
+
+ static LPISO8601DateFormatter *dateFormat = nil;
+ if (dateFormat == nil)
+ {
+ dateFormat = [[LPISO8601DateFormatter alloc] init];
+ [dateFormat setIncludeTime:YES];
+ }
+
+ NSString *str = [dateFormat stringFromDate:(NSDate*)inObject];
+ NSArray *comps = [str componentsSeparatedByString:@"+"];
+ NSString *dt = [comps objectAtIndex:0];
+ NSString *tz = [comps objectAtIndex:1];
+ NSRange rStart = NSMakeRange(0, 2);
+ NSString *first = [tz substringWithRange:rStart];
+ NSString *rest = [tz substringFromIndex:2];
+ str = [NSString stringWithFormat:@"%@+%@:%@",dt,first,rest];
+ theResult = [self serializeString:str error:outError];
+ }
else if ([inObject respondsToSelector:@selector(JSONDataRepresentation)])
{
theResult = [inObject JSONDataRepresentation];
@@ -0,0 +1,79 @@
+/*LPISO8601DateFormatter.h
+ *
+ *Created by Peter Hosey on 2009-04-11.
+ *Copyright 2009 Peter Hosey. All rights reserved.
+ */
+
+#import <Foundation/Foundation.h>
+
+/*This class converts dates to and from ISO 8601 strings. A good introduction to ISO 8601: <http://www.cl.cam.ac.uk/~mgk25/iso-time.html>
+ *
+ *Parsing can be done strictly, or not. When you parse loosely, leading whitespace is ignored, as is anything after the date.
+ *The loose parser will return an NSDate for this string: @" \t\r\n\f\t 2006-03-02!!!"
+ *Leading non-whitespace will not be ignored; the string will be rejected, and nil returned. See the README that came with this addition.
+ *
+ *The strict parser will only accept a string if the date is the entire string. The above string would be rejected immediately, solely on these grounds.
+ *Also, the loose parser provides some extensions that the strict parser doesn't.
+ *For example, the standard says for "-DDD" (an ordinal date in the implied year) that the logical representation (meaning, hierarchically) would be "--DDD", but because that extra hyphen is "superfluous", it was omitted.
+ *The loose parser will accept the extra hyphen; the strict parser will not.
+ *A full list of these extensions is in the README file.
+ */
+
+/*The format to either expect or produce.
+ *Calendar format is YYYY-MM-DD.
+ *Ordinal format is YYYY-DDD, where DDD ranges from 1 to 366; for example, 2009-32 is 2009-02-01.
+ *Week format is YYYY-Www-D, where ww ranges from 1 to 53 (the 'W' is literal) and D ranges from 1 to 7; for example, 2009-W05-07.
+ */
+enum {
+ LPISO8601DateFormatCalendar,
+ LPISO8601DateFormatOrdinal,
+ LPISO8601DateFormatWeek,
+};
+typedef NSUInteger LPISO8601DateFormat;
+
+//The default separator for time values. Currently, this is ':'.
+extern unichar ISO8601DefaultTimeSeparatorCharacter;
+
+@interface LPISO8601DateFormatter: NSFormatter
+{
+ NSString *lastUsedFormatString;
+ NSDateFormatter *unparsingFormatter;
+
+ NSCalendar *parsingCalendar, *unparsingCalendar;
+
+ NSTimeZone *defaultTimeZone;
+ LPISO8601DateFormat format;
+ unichar timeSeparator;
+ BOOL includeTime;
+ BOOL parsesStrictly;
+}
+
+//Call this if you get a memory warning.
++ (void) purgeGlobalCaches;
+
+@property(nonatomic, retain) NSTimeZone *defaultTimeZone;
+
+#pragma mark Parsing
+
+//As a formatter, this object converts strings to dates.
+
+@property BOOL parsesStrictly;
+
+- (NSDateComponents *) dateComponentsFromString:(NSString *)string;
+- (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone;
+- (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange;
+
+- (NSDate *) dateFromString:(NSString *)string;
+- (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone;
+- (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange;
+
+#pragma mark Unparsing
+
+@property LPISO8601DateFormat format;
+@property BOOL includeTime;
+@property unichar timeSeparator;
+
+- (NSString *) stringFromDate:(NSDate *)date;
+- (NSString *) stringFromDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone;
+
+@end
Oops, something went wrong.

0 comments on commit 2f00a23

Please sign in to comment.