From b19e155b0adf4476281d2ea9467e056d38fa8f31 Mon Sep 17 00:00:00 2001 From: Isaac Greenspan Date: Tue, 28 Oct 2014 15:49:29 -0500 Subject: [PATCH 01/12] Better .gitignore. --- .gitignore | 173 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 161 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 16703a6..e63e8cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,172 @@ -# OS X +######################### +# .gitignore file for Xcode4 and Xcode5 Source projects +# +# Apple bugs, waiting for Apple to fix/respond: +# +# 15564624 - what does the xccheckout file in Xcode5 do? Where's the documentation? +# +# Version 2.1 +# For latest version, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects +# +# 2013 updates: +# - fixed the broken "save personal Schemes" +# - added line-by-line explanations for EVERYTHING (some were missing) +# +# NB: if you are storing "built" products, this WILL NOT WORK, +# and you should use a different .gitignore (or none at all) +# This file is for SOURCE projects, where there are many extra +# files that we want to exclude +# +######################### + +##### +# OS X temporary files that should never be committed +# +# c.f. http://www.westwind.com/reference/os-x/invisibles.html + .DS_Store -# Xcode +# c.f. http://www.westwind.com/reference/os-x/invisibles.html + +.Trashes + +# c.f. http://www.westwind.com/reference/os-x/invisibles.html + +*.swp + +# *.lock - this is used and abused by many editors for many different things. +# For the main ones I use (e.g. Eclipse), it should be excluded +# from source-control, but YMMV + +*.lock + +# ... but don't ignore the Podfile.lock or the Pods/Manifest.lock file +!Podfile.lock +!Pods/Manifest.lock + +# +# profile - REMOVED temporarily (on double-checking, this seems incorrect; I can't find it in OS X docs?) +#profile + + +#### +# Xcode temporary files that should never be committed +# +# NB: NIB/XIB files still exist even on Storyboard projects, so we want this... + +*~.nib + + +#### +# Xcode build files - +# +# NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData" + +DerivedData/ + +# NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build" + build/ + + +##### +# Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups) +# +# This is complicated: +# +# SOMETIMES you need to put this file in version control. +# Apple designed it poorly - if you use "custom executables", they are +# saved in this file. +# 99% of projects do NOT use those, so they do NOT want to version control this file. +# ..but if you're in the 1%, comment out the line "*.pbxuser" + +# .pbxuser: http://lists.apple.com/archives/xcode-users/2004/Jan/msg00193.html + *.pbxuser -!default.pbxuser + +# .mode1v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html + *.mode1v3 -!default.mode1v3 + +# .mode2v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html + *.mode2v3 -!default.mode2v3 + +# .perspectivev3: http://stackoverflow.com/questions/5223297/xcode-projects-what-is-a-perspectivev3-file + *.perspectivev3 + +# NB: also, whitelist the default ones, some projects need to use these +!default.pbxuser +!default.mode1v3 +!default.mode2v3 !default.perspectivev3 + + +#### +# Xcode 4 - semi-personal settings +# +# +# OPTION 1: --------------------------------- +# throw away ALL personal settings (including custom schemes! +# - unless they are "shared") +# +# NB: this is exclusive with OPTION 2 below xcuserdata -*.xccheckout -profile + +# OPTION 2: --------------------------------- +# get rid of ALL personal settings, but KEEP SOME OF THEM +# - NB: you must manually uncomment the bits you want to keep +# +# NB: this *requires* git v1.8.2 or above; you may need to upgrade to latest OS X, +# or manually install git over the top of the OS X version +# NB: this is exclusive with OPTION 1 above +# +#xcuserdata/**/* + +# (requires option 2 above): Personal Schemes +# +#!xcuserdata/**/xcschemes/* + +#### +# XCode 4 workspaces - more detailed +# +# Workspaces are important! They are a core feature of Xcode - don't exclude them :) +# +# Workspace layout is quite spammy. For reference: +# +# /(root)/ +# /(project-name).xcodeproj/ +# project.pbxproj +# /project.xcworkspace/ +# contents.xcworkspacedata +# /xcuserdata/ +# /(your name)/xcuserdatad/ +# UserInterfaceState.xcuserstate +# /xcsshareddata/ +# /xcschemes/ +# (shared scheme name).xcscheme +# /xcuserdata/ +# /(your name)/xcuserdatad/ +# (private scheme).xcscheme +# xcschememanagement.plist +# +# + +#### +# Xcode 4 - Deprecated classes +# +# Allegedly, if you manually "deprecate" your classes, they get moved here. +# +# We're using source-control, so this is a "feature" that we do not want! + *.moved-aside -DerivedData -*.hmap -*.ipa -# CocoaPods -Pods \ No newline at end of file +#### +# UNKNOWN: recommended by others, but I can't discover what these files are +# +# ...none. Everything is now explained. + + +# Also, ignore .xccheckout files, as they contain data about specific paths and remotes that doesn't feel right in the repo. -igreensp 20131230 +*.xccheckout From 3b6e19ead7bb4db1f48af7b2e30da7daab9d640d Mon Sep 17 00:00:00 2001 From: Isaac Greenspan Date: Tue, 28 Oct 2014 15:50:05 -0500 Subject: [PATCH 02/12] Adding GRMustache via cocoapods. --- Cat2Cat.xcodeproj/project.pbxproj | 53 + Cat2Cat.xcworkspace/contents.xcworkspacedata | 10 + Podfile | 5 + Podfile.lock | 13 + Pods/GRMustache/LICENSE | 7 + Pods/GRMustache/README.md | 72 + .../Expressions/GRMustacheExpression.m | 44 + .../GRMustacheExpressionVisitor_private.h | 39 + .../GRMustacheExpression_private.h | 66 + .../GRMustacheFilteredExpression.m | 89 + .../GRMustacheFilteredExpression_private.h | 58 + .../GRMustacheIdentifierExpression.m | 73 + .../GRMustacheIdentifierExpression_private.h | 47 + .../GRMustacheImplicitIteratorExpression.m | 53 + ...stacheImplicitIteratorExpression_private.h | 39 + .../Expressions/GRMustacheScopedExpression.m | 86 + .../GRMustacheScopedExpression_private.h | 52 + .../classes/Compiling/GRMustacheCompiler.m | 643 +++ .../Compiling/GRMustacheCompiler_private.h | 115 + .../GRMustacheInheritablePartialNode.m | 74 + ...GRMustacheInheritablePartialNode_private.h | 65 + .../GRMustacheInheritableSectionNode.m | 80 + ...GRMustacheInheritableSectionNode_private.h | 65 + .../TemplateAST/GRMustachePartialNode.m | 85 + .../GRMustachePartialNode_private.h | 59 + .../TemplateAST/GRMustacheSectionTag.m | 100 + .../GRMustacheSectionTag_private.h | 66 + .../Compiling/TemplateAST/GRMustacheTag.h | 150 + .../Compiling/TemplateAST/GRMustacheTag.m | 72 + .../TemplateAST/GRMustacheTag_private.h | 56 + .../TemplateAST/GRMustacheTemplateAST.m | 76 + .../GRMustacheTemplateASTNode_private.h | 75 + .../GRMustacheTemplateASTVisitor_private.h | 45 + .../GRMustacheTemplateAST_private.h | 75 + .../TemplateAST/GRMustacheTextNode.m | 70 + .../TemplateAST/GRMustacheTextNode_private.h | 50 + .../TemplateAST/GRMustacheVariableTag.m | 100 + .../GRMustacheVariableTag_private.h | 53 + .../Configuration/GRMustacheConfiguration.h | 296 ++ .../Configuration/GRMustacheConfiguration.m | 165 + .../GRMustacheConfiguration_private.h | 88 + Pods/GRMustache/src/classes/GRMustache.h | 174 + Pods/GRMustache/src/classes/GRMustache.m | 120 + .../src/classes/GRMustacheVersion.h | 44 + .../src/classes/GRMustache_private.h | 54 + .../Parsing/GRMustacheExpressionParser.m | 561 +++ .../GRMustacheExpressionParser_private.h | 44 + .../Parsing/GRMustacheTemplateParser.m | 528 +++ .../GRMustacheTemplateParser_private.h | 156 + .../src/classes/Parsing/GRMustacheToken.m | 63 + .../classes/Parsing/GRMustacheToken_private.h | 183 + .../src/classes/Rendering/GRMustacheContext.h | 482 +++ .../src/classes/Rendering/GRMustacheContext.m | 458 +++ .../Rendering/GRMustacheContext_private.h | 183 + .../GRMustacheExpressionInvocation.m | 135 + .../GRMustacheExpressionInvocation_private.h | 65 + .../src/classes/Rendering/GRMustacheFilter.h | 125 + .../src/classes/Rendering/GRMustacheFilter.m | 155 + .../Rendering/GRMustacheFilter_private.h | 64 + .../classes/Rendering/GRMustacheKeyAccess.m | 693 ++++ .../Rendering/GRMustacheKeyAccess_private.h | 65 + .../classes/Rendering/GRMustacheRendering.h | 130 + .../classes/Rendering/GRMustacheRendering.m | 608 +++ .../Rendering/GRMustacheRenderingEngine.m | 352 ++ .../GRMustacheRenderingEngine_private.h | 53 + .../Rendering/GRMustacheRendering_private.h | 157 + .../Rendering/GRMustacheSafeKeyAccess.h | 54 + .../classes/Rendering/GRMustacheTagDelegate.h | 84 + .../Services/GRMustacheExpressionGenerator.m | 69 + .../GRMustacheExpressionGenerator_private.h | 35 + .../Services/GRMustacheTemplateGenerator.m | 163 + .../GRMustacheTemplateGenerator_private.h | 42 + .../classes/Services/NSFormatter+GRMustache.h | 70 + .../classes/Services/NSFormatter+GRMustache.m | 108 + .../Services/NSValueTransformer+GRMustache.h | 34 + .../Services/NSValueTransformer+GRMustache.m | 26 + .../StandardLibrary/GRMustacheEachFilter.m | 186 + .../GRMustacheEachFilter_private.h | 27 + .../StandardLibrary/GRMustacheHTMLLibrary.m | 107 + .../GRMustacheHTMLLibrary_private.h | 33 + .../GRMustacheJavascriptLibrary.m | 239 ++ .../GRMustacheJavascriptLibrary_private.h | 33 + .../StandardLibrary/GRMustacheLocalizer.h | 107 + .../StandardLibrary/GRMustacheLocalizer.m | 279 ++ .../GRMustacheStandardLibrary.m | 149 + .../GRMustacheStandardLibrary_private.h | 60 + .../StandardLibrary/GRMustacheURLLibrary.m | 141 + .../GRMustacheURLLibrary_private.h | 33 + .../Shared/GRMustacheAvailabilityMacros.h | 291 ++ .../GRMustacheAvailabilityMacros_private.h | 50 + .../classes/Shared/GRMustacheBuffer_private.h | 88 + .../classes/Shared/GRMustacheContentType.h | 53 + .../src/classes/Shared/GRMustacheError.h | 71 + .../src/classes/Shared/GRMustacheError.m | 28 + .../Shared/GRMustacheTranslateCharacters.m | 93 + .../GRMustacheTranslateCharacters_private.h | 27 + .../classes/Templates/GRMustacheTemplate.h | 383 ++ .../classes/Templates/GRMustacheTemplate.m | 152 + .../Templates/GRMustacheTemplateRepository.h | 576 +++ .../Templates/GRMustacheTemplateRepository.m | 558 +++ .../GRMustacheTemplateRepository_private.h | 107 + .../Templates/GRMustacheTemplate_private.h | 84 + Pods/Headers/Public/GRMustache/GRMustache.h | 1 + .../GRMustache/GRMustacheAvailabilityMacros.h | 1 + .../GRMustache/GRMustacheConfiguration.h | 1 + .../Public/GRMustache/GRMustacheContentType.h | 1 + .../Public/GRMustache/GRMustacheContext.h | 1 + .../Public/GRMustache/GRMustacheError.h | 1 + .../Public/GRMustache/GRMustacheFilter.h | 1 + .../Public/GRMustache/GRMustacheLocalizer.h | 1 + .../Public/GRMustache/GRMustacheRendering.h | 1 + .../GRMustache/GRMustacheSafeKeyAccess.h | 1 + .../Headers/Public/GRMustache/GRMustacheTag.h | 1 + .../Public/GRMustache/GRMustacheTagDelegate.h | 1 + .../Public/GRMustache/GRMustacheTemplate.h | 1 + .../GRMustache/GRMustacheTemplateRepository.h | 1 + .../Public/GRMustache/GRMustacheVersion.h | 1 + .../GRMustache/NSFormatter+GRMustache.h | 1 + .../NSValueTransformer+GRMustache.h | 1 + Pods/Headers/Public/JRSwizzle/JRSwizzle.h | 1 + Pods/JRSwizzle/JRSwizzle.h | 13 + Pods/JRSwizzle/JRSwizzle.m | 134 + Pods/JRSwizzle/README.markdown | 151 + Pods/Manifest.lock | 13 + Pods/Pods.xcodeproj/project.pbxproj | 3663 +++++++++++++++++ .../Pods-GRMustache-Private.xcconfig | 5 + .../Pods-GRMustache/Pods-GRMustache-dummy.m | 5 + .../Pods-GRMustache-prefix.pch | 5 + .../Pods-GRMustache/Pods-GRMustache.xcconfig | 1 + .../Pods-JRSwizzle-Private.xcconfig | 5 + .../Pods-JRSwizzle/Pods-JRSwizzle-dummy.m | 5 + .../Pods-JRSwizzle/Pods-JRSwizzle-prefix.pch | 5 + .../Pods-JRSwizzle/Pods-JRSwizzle.xcconfig | 1 + .../Pods/Pods-acknowledgements.markdown | 14 + .../Pods/Pods-acknowledgements.plist | 44 + Pods/Target Support Files/Pods/Pods-dummy.m | 5 + .../Pods/Pods-environment.h | 20 + .../Pods/Pods-resources.sh | 70 + .../Pods/Pods.debug.xcconfig | 6 + .../Pods/Pods.release.xcconfig | 6 + 140 files changed, 18010 insertions(+) create mode 100644 Cat2Cat.xcworkspace/contents.xcworkspacedata create mode 100644 Podfile create mode 100644 Podfile.lock create mode 100644 Pods/GRMustache/LICENSE create mode 100644 Pods/GRMustache/README.md create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression.m create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpressionVisitor_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression.m create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression.m create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression.m create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression.m create mode 100644 Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler.m create mode 100644 Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode.m create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode.m create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode.m create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag.m create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.m create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateAST.m create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTNode_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTVisitor_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateAST_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode.m create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode_private.h create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag.m create mode 100644 Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag_private.h create mode 100644 Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.h create mode 100644 Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.m create mode 100644 Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration_private.h create mode 100644 Pods/GRMustache/src/classes/GRMustache.h create mode 100644 Pods/GRMustache/src/classes/GRMustache.m create mode 100644 Pods/GRMustache/src/classes/GRMustacheVersion.h create mode 100644 Pods/GRMustache/src/classes/GRMustache_private.h create mode 100644 Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser.m create mode 100644 Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser_private.h create mode 100644 Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser.m create mode 100644 Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser_private.h create mode 100644 Pods/GRMustache/src/classes/Parsing/GRMustacheToken.m create mode 100644 Pods/GRMustache/src/classes/Parsing/GRMustacheToken_private.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheContext.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheContext.m create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheContext_private.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation.m create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation_private.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.m create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheFilter_private.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheKeyAccess.m create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheKeyAccess_private.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.m create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine.m create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine_private.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheRendering_private.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheSafeKeyAccess.h create mode 100644 Pods/GRMustache/src/classes/Rendering/GRMustacheTagDelegate.h create mode 100644 Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator.m create mode 100644 Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator_private.h create mode 100644 Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator.m create mode 100644 Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator_private.h create mode 100644 Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.h create mode 100644 Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.m create mode 100644 Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.h create mode 100644 Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.m create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter.m create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter_private.h create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary.m create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary_private.h create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheJavascriptLibrary.m create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheJavascriptLibrary_private.h create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheLocalizer.h create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheLocalizer.m create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheStandardLibrary.m create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheStandardLibrary_private.h create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheURLLibrary.m create mode 100644 Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheURLLibrary_private.h create mode 100644 Pods/GRMustache/src/classes/Shared/GRMustacheAvailabilityMacros.h create mode 100644 Pods/GRMustache/src/classes/Shared/GRMustacheAvailabilityMacros_private.h create mode 100644 Pods/GRMustache/src/classes/Shared/GRMustacheBuffer_private.h create mode 100644 Pods/GRMustache/src/classes/Shared/GRMustacheContentType.h create mode 100644 Pods/GRMustache/src/classes/Shared/GRMustacheError.h create mode 100644 Pods/GRMustache/src/classes/Shared/GRMustacheError.m create mode 100644 Pods/GRMustache/src/classes/Shared/GRMustacheTranslateCharacters.m create mode 100644 Pods/GRMustache/src/classes/Shared/GRMustacheTranslateCharacters_private.h create mode 100644 Pods/GRMustache/src/classes/Templates/GRMustacheTemplate.h create mode 100644 Pods/GRMustache/src/classes/Templates/GRMustacheTemplate.m create mode 100644 Pods/GRMustache/src/classes/Templates/GRMustacheTemplateRepository.h create mode 100644 Pods/GRMustache/src/classes/Templates/GRMustacheTemplateRepository.m create mode 100644 Pods/GRMustache/src/classes/Templates/GRMustacheTemplateRepository_private.h create mode 100644 Pods/GRMustache/src/classes/Templates/GRMustacheTemplate_private.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustache.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheAvailabilityMacros.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheConfiguration.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheContentType.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheContext.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheError.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheFilter.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheLocalizer.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheRendering.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheSafeKeyAccess.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheTag.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheTagDelegate.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheTemplate.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheTemplateRepository.h create mode 120000 Pods/Headers/Public/GRMustache/GRMustacheVersion.h create mode 120000 Pods/Headers/Public/GRMustache/NSFormatter+GRMustache.h create mode 120000 Pods/Headers/Public/GRMustache/NSValueTransformer+GRMustache.h create mode 120000 Pods/Headers/Public/JRSwizzle/JRSwizzle.h create mode 100644 Pods/JRSwizzle/JRSwizzle.h create mode 100644 Pods/JRSwizzle/JRSwizzle.m create mode 100644 Pods/JRSwizzle/README.markdown create mode 100644 Pods/Manifest.lock create mode 100644 Pods/Pods.xcodeproj/project.pbxproj create mode 100644 Pods/Target Support Files/Pods-GRMustache/Pods-GRMustache-Private.xcconfig create mode 100644 Pods/Target Support Files/Pods-GRMustache/Pods-GRMustache-dummy.m create mode 100644 Pods/Target Support Files/Pods-GRMustache/Pods-GRMustache-prefix.pch create mode 100644 Pods/Target Support Files/Pods-GRMustache/Pods-GRMustache.xcconfig create mode 100644 Pods/Target Support Files/Pods-JRSwizzle/Pods-JRSwizzle-Private.xcconfig create mode 100644 Pods/Target Support Files/Pods-JRSwizzle/Pods-JRSwizzle-dummy.m create mode 100644 Pods/Target Support Files/Pods-JRSwizzle/Pods-JRSwizzle-prefix.pch create mode 100644 Pods/Target Support Files/Pods-JRSwizzle/Pods-JRSwizzle.xcconfig create mode 100644 Pods/Target Support Files/Pods/Pods-acknowledgements.markdown create mode 100644 Pods/Target Support Files/Pods/Pods-acknowledgements.plist create mode 100644 Pods/Target Support Files/Pods/Pods-dummy.m create mode 100644 Pods/Target Support Files/Pods/Pods-environment.h create mode 100755 Pods/Target Support Files/Pods/Pods-resources.sh create mode 100644 Pods/Target Support Files/Pods/Pods.debug.xcconfig create mode 100644 Pods/Target Support Files/Pods/Pods.release.xcconfig diff --git a/Cat2Cat.xcodeproj/project.pbxproj b/Cat2Cat.xcodeproj/project.pbxproj index e65cb4a..68852ca 100644 --- a/Cat2Cat.xcodeproj/project.pbxproj +++ b/Cat2Cat.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 337C73DF188472F90078E5F8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 337C73DC188472F90078E5F8 /* main.m */; }; 337C73E0188472F90078E5F8 /* VICatalogWalker.m in Sources */ = {isa = PBXBuildFile; fileRef = 337C73DE188472F90078E5F8 /* VICatalogWalker.m */; }; 338287BE18773EC500070BE8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 338287BD18773EC500070BE8 /* Foundation.framework */; }; + EE0247AB4CA61B20873E6415 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D1E1AA0184C17C96B870929 /* libPods.a */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -25,6 +26,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0D1E1AA0184C17C96B870929 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 337C73DA188472E30078E5F8 /* Cat2Cat-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Cat2Cat-Prefix.pch"; path = "Cat2Cat/Cat2Cat-Prefix.pch"; sourceTree = SOURCE_ROOT; }; 337C73DB188472F00078E5F8 /* Cat2Cat.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; name = Cat2Cat.1; path = Cat2Cat/Cat2Cat.1; sourceTree = SOURCE_ROOT; }; 337C73DC188472F90078E5F8 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Cat2Cat/main.m; sourceTree = SOURCE_ROOT; }; @@ -33,6 +35,8 @@ 338287BA18773EC500070BE8 /* Cat2Cat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Cat2Cat; sourceTree = BUILT_PRODUCTS_DIR; }; 338287BD18773EC500070BE8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 33B0A501188089A20058939D /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.md; sourceTree = SOURCE_ROOT; }; + D92AAE9B5CFD31F7884B4371 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; + DA441151F5E8154C5647C333 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -41,6 +45,7 @@ buildActionMask = 2147483647; files = ( 338287BE18773EC500070BE8 /* Foundation.framework in Frameworks */, + EE0247AB4CA61B20873E6415 /* libPods.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -53,6 +58,7 @@ 338287BF18773EC500070BE8 /* ImageNamer */, 338287BC18773EC500070BE8 /* Frameworks */, 338287BB18773EC500070BE8 /* Products */, + EB0EBE335A298BE14F0158BF /* Pods */, ); sourceTree = ""; }; @@ -68,6 +74,7 @@ isa = PBXGroup; children = ( 338287BD18773EC500070BE8 /* Foundation.framework */, + 0D1E1AA0184C17C96B870929 /* libPods.a */, ); name = Frameworks; sourceTree = ""; @@ -93,6 +100,15 @@ name = "Supporting Files"; sourceTree = ""; }; + EB0EBE335A298BE14F0158BF /* Pods */ = { + isa = PBXGroup; + children = ( + D92AAE9B5CFD31F7884B4371 /* Pods.debug.xcconfig */, + DA441151F5E8154C5647C333 /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -100,9 +116,11 @@ isa = PBXNativeTarget; buildConfigurationList = 338287C818773EC500070BE8 /* Build configuration list for PBXNativeTarget "Cat2Cat" */; buildPhases = ( + 6F5AE2AA5307198823F4D6CC /* Check Pods Manifest.lock */, 338287B618773EC500070BE8 /* Sources */, 338287B718773EC500070BE8 /* Frameworks */, 338287B818773EC500070BE8 /* CopyFiles */, + 1464D5E34813F8ECCF73ABC8 /* Copy Pods Resources */, ); buildRules = ( ); @@ -139,6 +157,39 @@ }; /* End PBXProject section */ +/* Begin PBXShellScriptBuildPhase section */ + 1464D5E34813F8ECCF73ABC8 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 6F5AE2AA5307198823F4D6CC /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 338287B618773EC500070BE8 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -222,6 +273,7 @@ }; 338287C918773EC500070BE8 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = D92AAE9B5CFD31F7884B4371 /* Pods.debug.xcconfig */; buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Cat2Cat/Cat2Cat-Prefix.pch"; @@ -231,6 +283,7 @@ }; 338287CA18773EC500070BE8 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = DA441151F5E8154C5647C333 /* Pods.release.xcconfig */; buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Cat2Cat/Cat2Cat-Prefix.pch"; diff --git a/Cat2Cat.xcworkspace/contents.xcworkspacedata b/Cat2Cat.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..6557648 --- /dev/null +++ b/Cat2Cat.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..7cefa01 --- /dev/null +++ b/Podfile @@ -0,0 +1,5 @@ +source 'https://github.com/CocoaPods/Specs.git' + +platform :osx, "10.9" + +pod "GRMustache" diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..281a983 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,13 @@ +PODS: + - GRMustache (7.3.0): + - JRSwizzle (~> 1.0) + - JRSwizzle (1.0) + +DEPENDENCIES: + - GRMustache + +SPEC CHECKSUMS: + GRMustache: efecd3b603f0a7a99cf6bdf3998782ee0c465726 + JRSwizzle: 30da7a2c539a4ebf954b16d15f6dd8221c9f6fa5 + +COCOAPODS: 0.34.4 diff --git a/Pods/GRMustache/LICENSE b/Pods/GRMustache/LICENSE new file mode 100644 index 0000000..b3da59e --- /dev/null +++ b/Pods/GRMustache/LICENSE @@ -0,0 +1,7 @@ +Copyright (C) 2014 Gwendal Roué + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Pods/GRMustache/README.md b/Pods/GRMustache/README.md new file mode 100644 index 0000000..178fc0f --- /dev/null +++ b/Pods/GRMustache/README.md @@ -0,0 +1,72 @@ +GRMustache +========== + +GRMustache is an implementation of [Mustache templates](http://mustache.github.io/) for MacOS Cocoa and iOS. + +It ships with built-in goodies and extensibility hooks that let you avoid the strict minimalism of the genuine Mustache language when you need it. + +**System requirements**: GRMustache targets iOS down to version 4.3, MacOS down to 10.6 Snow Leopard (without garbage collection), and only depends on the Foundation framework. + +**September 13, 2014: GRMustache 7.3.0 is out.** [Release notes](RELEASE_NOTES.md) + + +Get release announcements and usage tips: follow [@GRMustache on Twitter](http://twitter.com/GRMustache). + + +How To +------ + +### 1. Setup your Xcode project + +You have three options, from the simplest to the hairiest: + +- [CocoaPods](Guides/installation.md#option-1-cocoapods) +- [Static Library](Guides/installation.md#option-2-static-library) +- [Compile the raw sources](Guides/installation.md#option-3-compiling-the-raw-sources) + + +### 2. Start rendering templates + +```objc +#import "GRMustache.h" +``` + +One-liners: + +```objc +// Renders "Hello Arthur!" +NSString *rendering = [GRMustacheTemplate renderObject:@{ @"name": @"Arthur" } fromString:@"Hello {{name}}!" error:NULL]; +``` + +```objc +// Renders the `Profile.mustache` resource of the main bundle +NSString *rendering = [GRMustacheTemplate renderObject:user fromResource:@"Profile" bundle:nil error:NULL]; +``` + +Reuse templates in order to avoid parsing the same template several times: + +```objc +GRMustacheTemplate *template = [GRMustacheTemplate templateFromResource:@"Profile" bundle:nil error:nil]; +rendering = [template renderObject:arthur error:NULL]; +rendering = [template renderObject:barbara error:NULL]; +rendering = ... +``` + +[GRMustachio](https://github.com/mugginsoft/GRMustachio) by Jonathan Mitchell is "A super simple, interactive GRMustache based application". It can help you design and test your templates. + + +Documentation +------------- + +If you don't know Mustache, start here: http://mustache.github.io/mustache.5.html + +- [Guides](Guides/README.md): a guided tour of GRMustache +- [Reference](http://groue.github.io/GRMustache/Reference/): all classes & protocols +- [Troubleshooting](Guides/troubleshooting.md) +- [FAQ](Guides/faq.md) + + +License +------- + +Released under the [MIT License](LICENSE). diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression.m b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression.m new file mode 100644 index 0000000..67470d5 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression.m @@ -0,0 +1,44 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpression_private.h" + +@implementation GRMustacheExpression +@synthesize token=_token; + +- (void)dealloc +{ + [_token release]; + [super dealloc]; +} + +- (BOOL)isEqual:(id)anObject +{ + return [super isEqual:anObject]; +} + +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error +{ + return YES; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpressionVisitor_private.h b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpressionVisitor_private.h new file mode 100644 index 0000000..a50b8c5 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpressionVisitor_private.h @@ -0,0 +1,39 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheFilteredExpression; +@class GRMustacheIdentifierExpression; +@class GRMustacheImplicitIteratorExpression; +@class GRMustacheScopedExpression; + +@protocol GRMustacheExpressionVisitor + +// Don't use these methods directly. Use -[GRMustacheExpression acceptVisitor:error:] instead +- (BOOL)visitFilteredExpression:(GRMustacheFilteredExpression *)expression error:(NSError **)error GRMUSTACHE_API_INTERNAL; +- (BOOL)visitIdentifierExpression:(GRMustacheIdentifierExpression *)expression error:(NSError **)error GRMUSTACHE_API_INTERNAL; +- (BOOL)visitImplicitIteratorExpression:(GRMustacheImplicitIteratorExpression *)expression error:(NSError **)error GRMUSTACHE_API_INTERNAL; +- (BOOL)visitScopedExpression:(GRMustacheScopedExpression *)expression error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression_private.h b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression_private.h new file mode 100644 index 0000000..b10ddb9 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheExpression_private.h @@ -0,0 +1,66 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheToken; +@protocol GRMustacheExpressionVisitor; + +/** + * The GRMustacheExpression is the base class for objects that represent + * Mustache expression such as `name`, `uppercase(name)`, or `user.name`. + */ +@interface GRMustacheExpression : NSObject { +@private + GRMustacheToken *_token; +} + +/** + * This property stores a token whose sole purpose is to help the library user + * debugging his templates, using the token's ability to output its location + * (`{{ foo }}` at line 23 of /path/to/template). + */ +@property (nonatomic, retain) GRMustacheToken *token GRMUSTACHE_API_INTERNAL; + +/** + * Returns a Boolean value that indicates whether the receiver and a given + * object are equal. + * + * Expressions are equal if and only if the result of their + * `hasValue:withContext:protected:error:` implementation would return the same + * value in a given rendering context. + * + * Default implementation is NSObject's one: subclasses must override. + * + * @param anObject The object to be compared to the receiver. + * + * @return YES if the receiver and anObject are equal, otherwise NO. + */ +- (BOOL)isEqual:(id)anObject; // no availability macro for Foundation method declaration + +/** + * Has the visitor visit the expression. + */ +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression.m b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression.m new file mode 100644 index 0000000..abbbc62 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression.m @@ -0,0 +1,89 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheFilteredExpression_private.h" +#import "GRMustacheExpressionVisitor_private.h" + +@implementation GRMustacheFilteredExpression +@synthesize filterExpression=_filterExpression; +@synthesize argumentExpression=_argumentExpression; +@synthesize curried=_curried; + ++ (instancetype)expressionWithFilterExpression:(GRMustacheExpression *)filterExpression argumentExpression:(GRMustacheExpression *)argumentExpression curried:(BOOL)curried +{ + return [[[self alloc] initWithFilterExpression:filterExpression argumentExpression:argumentExpression curried:curried] autorelease]; +} + +- (void)dealloc +{ + [_filterExpression release]; + [_argumentExpression release]; + [super dealloc]; +} + + +#pragma mark - GRMustacheExpression + +- (void)setToken:(GRMustacheToken *)token +{ + [super setToken:token]; + _filterExpression.token = token; + _argumentExpression.token = token; +} + +- (BOOL)isEqual:(id)expression +{ + if (![expression isKindOfClass:[GRMustacheFilteredExpression class]]) { + return NO; + } + if (![_filterExpression isEqual:((GRMustacheFilteredExpression *)expression).filterExpression]) { + return NO; + } + return [_argumentExpression isEqual:((GRMustacheFilteredExpression *)expression).argumentExpression]; +} + +- (NSUInteger)hash +{ + return [_filterExpression hash] ^ [_argumentExpression hash]; +} + +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitFilteredExpression:self error:error]; +} + + +#pragma mark - Private + +- (instancetype)initWithFilterExpression:(GRMustacheExpression *)filterExpression argumentExpression:(GRMustacheExpression *)argumentExpression curried:(BOOL)curried +{ + self = [super init]; + if (self) { + _filterExpression = [filterExpression retain]; + _argumentExpression = [argumentExpression retain]; + _curried = curried; + } + return self; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression_private.h b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression_private.h new file mode 100644 index 0000000..1b2f8e5 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheFilteredExpression_private.h @@ -0,0 +1,58 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpression_private.h" + +/** + * The GRMustacheFilteredExpression represents expressions such as + * `()`. + */ +@interface GRMustacheFilteredExpression : GRMustacheExpression { +@private + GRMustacheExpression *_filterExpression; + GRMustacheExpression *_argumentExpression; + BOOL _curried; +} + +@property (nonatomic, retain, readonly) GRMustacheExpression *filterExpression GRMUSTACHE_API_INTERNAL; +@property (nonatomic, retain, readonly) GRMustacheExpression *argumentExpression GRMUSTACHE_API_INTERNAL; +@property (nonatomic, getter=isCurried, readonly) BOOL curried GRMUSTACHE_API_INTERNAL; + +/** + * Returns a filtered expression, given an expression that returns a filter, and + * an expression that return the filter argument. + * + * For example, the Mustache tag `{{ f(x) }}` contains a filtered expression, + * whose filterExpression is a GRMustacheIdentifierExpression (for the + * identifier `f`), and whose argumentExpression is a + * GRMustacheIdentifierExpression (for the identifier `x`). + * + * @param filterExpression An expression whose value is an object conforming + * to the protocol. + * @param argumentExpression An expression whose value is the argument of the + * filter. + * @param curried If YES, this expression must evaluate to a filter. + * + * @return A GRMustacheFilteredExpression. + */ ++ (instancetype)expressionWithFilterExpression:(GRMustacheExpression *)filterExpression argumentExpression:(GRMustacheExpression *)argumentExpression curried:(BOOL)curried GRMUSTACHE_API_INTERNAL; +@end diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression.m b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression.m new file mode 100644 index 0000000..43055b6 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression.m @@ -0,0 +1,73 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheIdentifierExpression_private.h" +#import "GRMustacheExpressionVisitor_private.h" + +@implementation GRMustacheIdentifierExpression +@synthesize identifier=_identifier; + ++ (instancetype)expressionWithIdentifier:(NSString *)identifier +{ + return [[[self alloc] initWithIdentifier:identifier] autorelease]; +} + +- (void)dealloc +{ + [_identifier release]; + [super dealloc]; +} + + +#pragma mark - GRMustacheExpression + +- (BOOL)isEqual:(id)expression +{ + if (![expression isKindOfClass:[GRMustacheIdentifierExpression class]]) { + return NO; + } + return [_identifier isEqual:((GRMustacheIdentifierExpression *)expression).identifier]; +} + +- (NSUInteger)hash +{ + return [_identifier hash]; +} + +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitIdentifierExpression:self error:error]; +} + + +#pragma mark - Private + +- (instancetype)initWithIdentifier:(NSString *)identifier +{ + self = [super init]; + if (self) { + _identifier = [identifier retain]; + } + return self; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression_private.h b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression_private.h new file mode 100644 index 0000000..a72831c --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheIdentifierExpression_private.h @@ -0,0 +1,47 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpression_private.h" + +/** + * The GRMustacheIdentifierExpression represents expressions such as + * `identifier`. + */ +@interface GRMustacheIdentifierExpression : GRMustacheExpression { +@private + NSString *_identifier; +} + +@property (nonatomic, retain, readonly) NSString *identifier GRMUSTACHE_API_INTERNAL; + +/** + * Returns an identifier expression, given an identifier. + * + * For example, the Mustache tag `{{ name }}` contains an identifier + * expression, whose identifier is `name`. + * + * @param identifier An identifier + * + * @return A GRMustacheIdentifierExpression. + */ ++ (instancetype)expressionWithIdentifier:(NSString *)identifier GRMUSTACHE_API_INTERNAL; +@end diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression.m b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression.m new file mode 100644 index 0000000..b28fc78 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression.m @@ -0,0 +1,53 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheImplicitIteratorExpression_private.h" +#import "GRMustacheExpressionVisitor_private.h" + +static GRMustacheImplicitIteratorExpression *instance; + +@implementation GRMustacheImplicitIteratorExpression + ++ (void)initialize +{ + instance = [[self alloc] init]; +} + ++ (instancetype)expression +{ + return instance; +} + + +#pragma mark - GRMustacheExpression + +- (BOOL)isEqual:(id)expression +{ + return expression == instance; +} + +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitImplicitIteratorExpression:self error:error]; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression_private.h b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression_private.h new file mode 100644 index 0000000..cd1bd6d --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheImplicitIteratorExpression_private.h @@ -0,0 +1,39 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpression_private.h" + +/** + * The GRMustacheImplicitIteratorExpression represents the `.` expression. + */ +@interface GRMustacheImplicitIteratorExpression : GRMustacheExpression + +/** + * Returns an "implicit iterator" expression. + * + * For example, the Mustache tag `{{ . }}` contains an implicit iterator + * expression. + * + * @return A GRMustacheImplicitIteratorExpression. + */ ++ (instancetype)expression GRMUSTACHE_API_INTERNAL; +@end diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression.m b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression.m new file mode 100644 index 0000000..204d415 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression.m @@ -0,0 +1,86 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheScopedExpression_private.h" +#import "GRMustacheExpressionVisitor_private.h" + + +@implementation GRMustacheScopedExpression +@synthesize baseExpression=_baseExpression; +@synthesize identifier=_identifier; + ++ (instancetype)expressionWithBaseExpression:(GRMustacheExpression *)baseExpression identifier:(NSString *)identifier +{ + return [[[self alloc] initWithBaseExpression:baseExpression identifier:identifier] autorelease]; +} + +- (void)dealloc +{ + [_baseExpression release]; + [_identifier release]; + [super dealloc]; +} + + +#pragma mark - GRMustacheExpression + +- (void)setToken:(GRMustacheToken *)token +{ + [super setToken:token]; + _baseExpression.token = token; +} + +- (BOOL)isEqual:(id)expression +{ + if (![expression isKindOfClass:[GRMustacheScopedExpression class]]) { + return NO; + } + if (![_baseExpression isEqual:((GRMustacheScopedExpression *)expression).baseExpression]) { + return NO; + } + return [_identifier isEqual:((GRMustacheScopedExpression *)expression).identifier]; +} + +- (NSUInteger)hash +{ + return [_baseExpression hash] ^ [_identifier hash]; +} + +- (BOOL)acceptVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitScopedExpression:self error:error]; +} + + +#pragma mark - Private + +- (instancetype)initWithBaseExpression:(GRMustacheExpression *)baseExpression identifier:(NSString *)identifier +{ + self = [super init]; + if (self) { + _baseExpression = [baseExpression retain]; + _identifier = [identifier retain]; + } + return self; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression_private.h b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression_private.h new file mode 100644 index 0000000..282c556 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/Expressions/GRMustacheScopedExpression_private.h @@ -0,0 +1,52 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpression_private.h" + +/** + * The GRMustacheScopedExpression represents expressions such as + * `.identifier`. + */ +@interface GRMustacheScopedExpression : GRMustacheExpression { +@private + GRMustacheExpression *_baseExpression; + NSString *_identifier; +} + +@property (nonatomic, retain, readonly) GRMustacheExpression *baseExpression GRMUSTACHE_API_INTERNAL; +@property (nonatomic, retain, readonly) NSString *identifier GRMUSTACHE_API_INTERNAL; + +/** + * Returns a scoped expression, given an expression that returns a value, and + * an identifier. + * + * For example, the Mustache tag `{{ person.name }}` contains a scoped + * expression, whose baseExpression is a GRMustacheIdentifierExpression (for the + * identifier `person`), and whose identifier is `name`. + * + * @param baseExpression An expression. + * @param identifier An identifier. + * + * @return A GRMustacheScopedExpression. + */ ++ (instancetype)expressionWithBaseExpression:(GRMustacheExpression *)baseExpression identifier:(NSString *)identifier GRMUSTACHE_API_INTERNAL; +@end diff --git a/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler.m b/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler.m new file mode 100644 index 0000000..54fb10d --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler.m @@ -0,0 +1,643 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheCompiler_private.h" +#import "GRMustachePartialNode_private.h" +#import "GRMustacheTemplateRepository_private.h" +#import "GRMustacheTextNode_private.h" +#import "GRMustacheVariableTag_private.h" +#import "GRMustacheSectionTag_private.h" +#import "GRMustacheInheritableSectionNode_private.h" +#import "GRMustacheInheritablePartialNode_private.h" +#import "GRMustacheExpressionParser_private.h" +#import "GRMustacheExpression_private.h" +#import "GRMustacheToken_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheError.h" + +@interface GRMustacheCompiler() + +/** + * The fatal error that should be returned by the public method + * ASTNodesReturningError:. + * + * @see currentASTNodes + */ +@property (nonatomic, retain) NSError *fatalError; + +/** + * After an opening token has been found such as {{#A}}, {{^B}}, or {{ 0, @"WTF empty GRMustacheTokenTypeContent"); + + // Success: append GRMustacheTextASTNode + [_currentASTNodes addObject:[GRMustacheTextNode textNodeWithText:token.templateSubstring]]; + break; + + + case GRMustacheTokenTypeEscapedVariable: { + // Expression validation + NSError *error; + GRMustacheExpressionParser *expressionParser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [expressionParser parseExpression:token.tagInnerContent empty:NULL error:&error]; + if (expression == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:error.localizedDescription]]; + return NO; + } + + // Success: append GRMustacheVariableTag + expression.token = token; + [_currentASTNodes addObject:[GRMustacheVariableTag variableTagWithExpression:expression escapesHTML:YES contentType:_contentType]]; + + // lock _contentType + _contentTypeLocked = YES; + } break; + + + case GRMustacheTokenTypeUnescapedVariable: { + // Expression validation + NSError *error; + GRMustacheExpressionParser *expressionParser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [expressionParser parseExpression:token.tagInnerContent empty:NULL error:&error]; + if (expression == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:error.localizedDescription]]; + return NO; + } + + // Success: append GRMustacheVariableTag + expression.token = token; + [_currentASTNodes addObject:[GRMustacheVariableTag variableTagWithExpression:expression escapesHTML:NO contentType:_contentType]]; + + // lock _contentType + _contentTypeLocked = YES; + } break; + + + case GRMustacheTokenTypeSectionOpening: { + // Expression validation + NSError *error; + BOOL empty; + GRMustacheExpressionParser *expressionParser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [expressionParser parseExpression:token.tagInnerContent empty:&empty error:&error]; + + if (_currentOpeningToken && + _currentOpeningToken.type == GRMustacheTokenTypeInvertedSectionOpening && + ((expression == nil && empty) || (expression != nil && [expression isEqual:_currentTagValue]))) + { + // We found the "else" close of an inverted section: + // {{^foo}}...{{#}}... + // {{^foo}}...{{#foo}}... + + // Insert a new inverted section and prepare a regular one + + NSRange openingTokenRange = _currentOpeningToken.range; + NSRange innerRange = NSMakeRange(openingTokenRange.location + openingTokenRange.length, token.range.location - (openingTokenRange.location + openingTokenRange.length)); + GRMustacheTemplateAST *templateAST = [GRMustacheTemplateAST templateASTWithASTNodes:_currentASTNodes contentType:_contentType]; + GRMustacheSectionTag *sectionTag = [GRMustacheSectionTag sectionTagWithExpression:(GRMustacheExpression *)_currentTagValue + inverted:YES + templateString:token.templateString + innerRange:innerRange + templateAST:templateAST]; + + [_openingTokenStack removeLastObject]; + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + [_ASTNodesStack removeLastObject]; + [[_ASTNodesStack lastObject] addObject:sectionTag]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + } else { + // This is a new regular section + + // Validate expression + if (expression == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:error.localizedDescription]]; + return NO; + } + + // Prepare a new section + + expression.token = token; + self.currentTagValue = expression; + [_tagValueStack addObject:_currentTagValue]; + + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + // lock _contentType + _contentTypeLocked = YES; + } + } break; + + + case GRMustacheTokenTypeInvertedSectionOpening: { + // Expression validation + NSError *error; + BOOL empty; + GRMustacheExpressionParser *expressionParser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [expressionParser parseExpression:token.tagInnerContent empty:&empty error:&error]; + + if (_currentOpeningToken && + _currentOpeningToken.type == GRMustacheTokenTypeSectionOpening && + ((expression == nil && empty) || (expression != nil && [expression isEqual:_currentTagValue]))) + { + // We found the "else" close of a regular or inheritable section: + // {{#foo}}...{{^}}...{{/foo}} + // {{#foo}}...{{^foo}}...{{/foo}} + + // Insert a new section and prepare an inverted one + + NSRange openingTokenRange = _currentOpeningToken.range; + NSRange innerRange = NSMakeRange(openingTokenRange.location + openingTokenRange.length, token.range.location - (openingTokenRange.location + openingTokenRange.length)); + GRMustacheTemplateAST *templateAST = [GRMustacheTemplateAST templateASTWithASTNodes:_currentASTNodes contentType:_contentType]; + GRMustacheSectionTag *sectionTag = [GRMustacheSectionTag sectionTagWithExpression:(GRMustacheExpression *)_currentTagValue + inverted:NO + templateString:token.templateString + innerRange:innerRange + templateAST:templateAST]; + + [_openingTokenStack removeLastObject]; + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + [_ASTNodesStack removeLastObject]; + [[_ASTNodesStack lastObject] addObject:sectionTag]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + } else { + // This is a new inverted section + + // Validate expression + if (expression == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:error.localizedDescription]]; + return NO; + } + + // Prepare a new section + + expression.token = token; + self.currentTagValue = expression; + [_tagValueStack addObject:_currentTagValue]; + + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + // lock _contentType + _contentTypeLocked = YES; + } + } break; + + + case GRMustacheTokenTypeInheritableSectionOpening: { + // Inheritable section name validation + NSError *inheritableSectionError; + NSString *name = [parser parseInheritableSectionName:token.tagInnerContent empty:NULL error:&inheritableSectionError]; + if (name == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"%@ in inheritable section tag", inheritableSectionError.localizedDescription]]]; + return NO; + } + + // Expand stacks + self.currentTagValue = name; + [_tagValueStack addObject:_currentTagValue]; + + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + // lock _contentType + _contentTypeLocked = YES; + } break; + + + case GRMustacheTokenTypeInheritablePartial: { + // Partial name validation + NSError *partialError; + NSString *partialName = [parser parseTemplateName:token.tagInnerContent empty:NULL error:&partialError]; + if (partialName == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"%@ in partial tag", partialError.localizedDescription]]]; + return NO; + } + + // Expand stacks + self.currentTagValue = partialName; + [_tagValueStack addObject:_currentTagValue]; + + self.currentOpeningToken = token; + [_openingTokenStack addObject:_currentOpeningToken]; + + self.currentASTNodes = [[[NSMutableArray alloc] initWithCapacity:20] autorelease]; + [_ASTNodesStack addObject:_currentASTNodes]; + + // lock _contentType + _contentTypeLocked = YES; + } break; + + + case GRMustacheTokenTypeClosing: { + if (_currentOpeningToken == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"Unexpected %@ closing tag", token.templateSubstring]]]; + return NO; + } + + // What are we closing? + + id wrapperASTNode = nil; + switch (_currentOpeningToken.type) { + case GRMustacheTokenTypeSectionOpening: + case GRMustacheTokenTypeInvertedSectionOpening: { + // Expression validation + // We need a valid expression that matches section opening, + // or an empty `{{/}}` closing tags. + NSError *error; + BOOL empty; + GRMustacheExpressionParser *expressionParser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [expressionParser parseExpression:token.tagInnerContent empty:&empty error:&error]; + if (expression == nil && !empty) { + [self failWithFatalError:[self parseErrorAtToken:token description:error.localizedDescription]]; + return NO; + } + + NSAssert(_currentTagValue, @"WTF expected _currentTagValue"); + if (expression && ![expression isEqual:_currentTagValue]) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"Unexpected %@ closing tag", token.templateSubstring]]]; + return NO; + } + + // Nothing prevents tokens to come from different template strings. + // We, however, do not support this case, because GRMustacheSectionTag + // builds from a single template string and a single innerRange. + if (_currentOpeningToken.templateString != token.templateString) { + [NSException raise:NSInternalInconsistencyException format:@"Support for tokens coming from different strings is not implemented."]; + } + + // Success: create new GRMustacheSectionTag + NSRange openingTokenRange = _currentOpeningToken.range; + NSRange innerRange = NSMakeRange(openingTokenRange.location + openingTokenRange.length, token.range.location - (openingTokenRange.location + openingTokenRange.length)); + GRMustacheTemplateAST *templateAST = [GRMustacheTemplateAST templateASTWithASTNodes:_currentASTNodes contentType:_contentType]; + wrapperASTNode = [GRMustacheSectionTag sectionTagWithExpression:(GRMustacheExpression *)_currentTagValue + inverted:(_currentOpeningToken.type == GRMustacheTokenTypeInvertedSectionOpening) + templateString:token.templateString + innerRange:innerRange + templateAST:templateAST]; + } break; + + case GRMustacheTokenTypeInheritableSectionOpening: { + // Inheritable section name validation + // We need a valid name that matches section opening, + // or an empty `{{/}}` closing tags. + NSError *error; + BOOL empty; + NSString *name = [parser parseInheritableSectionName:token.tagInnerContent empty:&empty error:&error]; + if (name && ![name isEqual:_currentTagValue]) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"Unexpected %@ closing tag", token.templateSubstring]]]; + return NO; + } else if (!name && !empty) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"%@ in partial closing tag", error.localizedDescription]]]; + return NO; + } + + if (name && ![name isEqual:_currentTagValue]) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"Unexpected %@ closing tag", token.templateSubstring]]]; + return NO; + } + + // Success: create new GRMustacheInheritableSection + GRMustacheTemplateAST *templateAST = [GRMustacheTemplateAST templateASTWithASTNodes:_currentASTNodes contentType:_contentType]; + wrapperASTNode = [GRMustacheInheritableSectionNode inheritableSectionNodeWithName:(NSString *)_currentTagValue templateAST:templateAST]; + } break; + + case GRMustacheTokenTypeInheritablePartial: { + // Validate token: inheritable template ending should be missing, or match inheritable template opening + NSError *error; + BOOL empty; + NSString *partialName = [parser parseTemplateName:token.tagInnerContent empty:&empty error:&error]; + if (partialName && ![partialName isEqual:_currentTagValue]) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"Unexpected %@ closing tag", token.templateSubstring]]]; + return NO; + } else if (!partialName && !empty) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"%@ in partial closing tag", error.localizedDescription]]]; + return NO; + } + + // Ask templateRepository for inheritable template + partialName = (NSString *)_currentTagValue; + GRMustacheTemplateAST *templateAST = [_templateRepository templateASTNamed:partialName relativeToTemplateID:_baseTemplateID error:&error]; + if (templateAST == nil) { + [self failWithFatalError:error]; + return NO; + } + + // Check for consistency of HTML safety + // + // If templateAST.isPlaceholder, this means that we are actually + // compiling it, and that template simply recursively refers to itself. + // Consistency of HTML safety is thus guaranteed. + // + // However, if templateAST.isPlaceholder is false, then we must ensure + // content type compatibility: an HTML template can not override a + // text one, and vice versa. + // + // See test "HTML template can not override TEXT template" in GRMustacheSuites/text_rendering.json + if (!templateAST.isPlaceholder && templateAST.contentType != _contentType) { + [self failWithFatalError:[self parseErrorAtToken:_currentOpeningToken description:@"HTML safety mismatch"]]; + return NO; + } + + // Success: create new GRMustacheInheritablePartialNode + GRMustachePartialNode *partialNode = [GRMustachePartialNode partialNodeWithTemplateAST:templateAST name:partialName]; + GRMustacheTemplateAST *overridingTemplateAST = [GRMustacheTemplateAST templateASTWithASTNodes:_currentASTNodes contentType:_contentType]; + wrapperASTNode = [GRMustacheInheritablePartialNode inheritablePartialNodeWithPartialNode:partialNode overridingTemplateAST:overridingTemplateAST]; + } break; + + default: + NSAssert(NO, @"WTF unexpected _currentOpeningToken.type"); + break; + } + + NSAssert(wrapperASTNode, @"WTF expected wrapperASTNode"); + + [_tagValueStack removeLastObject]; + self.currentTagValue = [_tagValueStack lastObject]; + + [_openingTokenStack removeLastObject]; + self.currentOpeningToken = [_openingTokenStack lastObject]; + + [_ASTNodesStack removeLastObject]; + self.currentASTNodes = [_ASTNodesStack lastObject]; + + [_currentASTNodes addObject:wrapperASTNode]; + } break; + + + case GRMustacheTokenTypePartial: { + // Partial name validation + NSError *partialError; + NSString *partialName = [parser parseTemplateName:token.tagInnerContent empty:NULL error:&partialError]; + if (partialName == nil) { + [self failWithFatalError:[self parseErrorAtToken:token description:[NSString stringWithFormat:@"%@ in partial tag", partialError.localizedDescription]]]; + return NO; + } + + // Ask templateRepository for partial template + GRMustacheTemplateAST *templateAST = [_templateRepository templateASTNamed:partialName relativeToTemplateID:_baseTemplateID error:&partialError]; + if (templateAST == nil) { + [self failWithFatalError:partialError]; + return NO; + } + + // Success: append ASTNode + GRMustachePartialNode *partialNode = [GRMustachePartialNode partialNodeWithTemplateAST:templateAST name:partialName]; + [_currentASTNodes addObject:partialNode]; + + // lock _contentType + _contentTypeLocked = YES; + } break; + + } + return YES; +} + +- (void)templateParser:(GRMustacheTemplateParser *)parser didFailWithError:(NSError *)error +{ + [self failWithFatalError:error]; +} + +#pragma mark Private + +/** + * This method is called whenever an error has occurred beyond any repair hope. + * + * @param fatalError The fatal error + */ +- (void)failWithFatalError:(NSError *)fatalError +{ + // Make sure ASTNodesReturningError: returns correct results: + self.fatalError = fatalError; + self.currentASTNodes = nil; + + // All those objects are useless, now + self.currentOpeningToken = nil; + self.currentTagValue = nil; + self.ASTNodesStack = nil; + self.openingTokenStack = nil; +} + +/** + * Builds and returns an NSError of domain GRMustacheErrorDomain, code + * GRMustacheErrorCodeParseError, related to a specific location in a template, + * represented by the token argument. + * + * @param token The GRMustacheToken where the parse error has been + * found. + * @param description A NSString that fills the NSLocalizedDescriptionKey key + * of the error's userInfo. + * + * @return An NSError + */ +- (NSError *)parseErrorAtToken:(GRMustacheToken *)token description:(NSString *)description +{ + NSString *localizedDescription; + if (token.templateID) { + localizedDescription = [NSString stringWithFormat:@"Parse error at line %lu of template %@: %@", (unsigned long)token.line, token.templateID, description]; + } else { + localizedDescription = [NSString stringWithFormat:@"Parse error at line %lu: %@", (unsigned long)token.line, description]; + } + return [NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:localizedDescription forKey:NSLocalizedDescriptionKey]]; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler_private.h b/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler_private.h new file mode 100644 index 0000000..60133c3 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/GRMustacheCompiler_private.h @@ -0,0 +1,115 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateParser_private.h" +#import "GRMustacheContentType.h" + +@class GRMustacheTemplateRepository; +@class GRMustacheTemplateAST; + +/** + * The GRMustacheCompiler interprets GRMustacheTokens provided by a + * GRMustacheTemplateParser, and outputs a syntax tree of objects conforming to + * the GRMustacheTemplateASTNode protocol. + * + * @see GRMustacheTemplateASTNode + * @see GRMustacheToken + * @see GRMustacheTemplateParser + */ +@interface GRMustacheCompiler : NSObject { +@private + NSError *_fatalError; + + NSMutableArray *_currentASTNodes; + NSMutableArray *_ASTNodesStack; + + GRMustacheToken *_currentOpeningToken; + NSMutableArray *_openingTokenStack; + + NSObject *_currentTagValue; + NSMutableArray *_tagValueStack; + + GRMustacheTemplateRepository *_templateRepository; + id _baseTemplateID; + GRMustacheContentType _contentType; + BOOL _contentTypeLocked; +} + +/** + * The template repository that provides partial templates to the compiler. + */ +@property (nonatomic, assign) GRMustacheTemplateRepository *templateRepository GRMUSTACHE_API_INTERNAL; + +/** + * ID of the currently compiled template + */ +@property (nonatomic, retain) id baseTemplateID GRMUSTACHE_API_INTERNAL; + +/** + * Returns an initialized compiler. + * + * @param contentType The contentType that affects the compilation phase. + * + * @return a compiler + */ +- (instancetype)initWithContentType:(GRMustacheContentType)contentType GRMUSTACHE_API_INTERNAL; + +/** + * Returns a Mustache Abstract Syntax Tree. + * + * The AST will contain something if a GRMustacheTemplateParser has provided + * GRMustacheToken instances to the compiler. + * + * For example: + * + * ``` + * // Create a Mustache compiler + * GRMustacheCompiler *compiler = [[[GRMustacheCompiler alloc] initWithContentType:...] autorelease]; + * + * // Some GRMustacheCompilerDataSource tells the compiler where are the + * // partials. + * compiler.dataSource = ...; + * + * // Create a Mustache parser + * GRMustacheTemplateParser *parser = [[[GRMustacheTemplateParser alloc] initWithContentType:...] autorelease]; + * + * // The parser feeds the compiler + * parser.delegate = compiler; + * + * // Parse some string + * [parser parseTemplateString:... templateID:...]; + * + * // Extract template ASTNodes from the compiler + * GRMustacheTemplateAST *templateAST = [compiler templateASTReturningError:...]; + * ``` + * + * @param error If there is an error building the abstract syntax tree, upon + * return contains an NSError object that describes the problem. + * + * @return A GRMustacheTemplateAST instance + * + * @see GRMustacheTemplateAST + */ +- (GRMustacheTemplateAST *)templateASTReturningError:(NSError **)error GRMUSTACHE_API_INTERNAL; +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode.m b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode.m new file mode 100644 index 0000000..7ba077a --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode.m @@ -0,0 +1,74 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheInheritablePartialNode_private.h" +#import "GRMustachePartialNode_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + +@implementation GRMustacheInheritablePartialNode +@synthesize overridingTemplateAST=_overridingTemplateAST; +@synthesize partialNode=_partialNode; + ++ (instancetype)inheritablePartialNodeWithPartialNode:(GRMustachePartialNode *)partialNode overridingTemplateAST:(GRMustacheTemplateAST *)overridingTemplateAST +{ + return [[[self alloc] initWithPartialNode:partialNode overridingTemplateAST:overridingTemplateAST] autorelease]; +} + +- (void)dealloc +{ + [_partialNode release]; + [_overridingTemplateAST release]; + [super dealloc]; +} + + +#pragma mark - GRMustacheTemplateASTNode + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitInheritablePartialNode:self error:error]; +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + // look for the last inheritable ASTNode in inner templateAST + for (id innerASTNode in _overridingTemplateAST.templateASTNodes) { + templateASTNode = [innerASTNode resolveTemplateASTNode:templateASTNode]; + } + return templateASTNode; +} + + +#pragma mark - Private + +- (instancetype)initWithPartialNode:(GRMustachePartialNode *)partialNode overridingTemplateAST:(GRMustacheTemplateAST *)overridingTemplateAST +{ + self = [super init]; + if (self) { + _partialNode = [partialNode retain]; + _overridingTemplateAST = [overridingTemplateAST retain]; + } + return self; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode_private.h b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode_private.h new file mode 100644 index 0000000..1dcc424 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritablePartialNode_private.h @@ -0,0 +1,65 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +@class GRMustachePartialNode; +@class GRMustacheTemplateAST; + +/** + * A GRMustacheInheritablePartialNode is an AST node that represents inheritable + * partials as `{{ { +@private + GRMustachePartialNode *_partialNode; + GRMustacheTemplateAST *_overridingTemplateAST; +} + +/** + * The overriding AST, built from the inner content of the inheritable partial + * node: + * + * {{< ... }} AST {{/ }} + */ +@property (nonatomic, retain, readonly) GRMustacheTemplateAST *overridingTemplateAST GRMUSTACHE_API_INTERNAL; + +/** + * The partial template that is inherited: + * + * {{< inherited_partial_template }}...{{/ }} + */ +@property (nonatomic, retain, readonly) GRMustachePartialNode *partialNode GRMUSTACHE_API_INTERNAL; + +/** + * Builds a GRMustacheInheritablePartialNode. + * + * @param partialNode The inherited partial. + * @param templateAST The AST that overrides the inherited partial template. + * + * @return A GRMustacheInheritablePartialNode + */ ++ (instancetype)inheritablePartialNodeWithPartialNode:(GRMustachePartialNode *)partialNode overridingTemplateAST:(GRMustacheTemplateAST *)overridingTemplateAST GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode.m b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode.m new file mode 100644 index 0000000..fbb7e26 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode.m @@ -0,0 +1,80 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheInheritableSectionNode_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + +@implementation GRMustacheInheritableSectionNode +@synthesize name=_name; +@synthesize templateAST=_templateAST; + ++ (instancetype)inheritableSectionNodeWithName:(NSString *)name templateAST:(GRMustacheTemplateAST *)templateAST +{ + return [[[self alloc] initWithName:name templateAST:templateAST] autorelease]; +} + +- (void)dealloc +{ + [_name release]; + [_templateAST release]; + [super dealloc]; +} + + +#pragma mark - + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitInheritableSectionNode:self error:error]; +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + // Inheritable section can only override inheritable section + if (![templateASTNode isKindOfClass:[GRMustacheInheritableSectionNode class]]) { + return templateASTNode; + } + GRMustacheInheritableSectionNode *otherSection = (GRMustacheInheritableSectionNode *)templateASTNode; + + // names must match + if (![otherSection.name isEqual:_name]) { + return otherSection; + } + + // OK, override with self + return self; +} + + +#pragma mark - Private + +- (instancetype)initWithName:(NSString *)name templateAST:(GRMustacheTemplateAST *)templateAST +{ + self = [self init]; + if (self) { + _name = [name retain]; + _templateAST = [templateAST retain]; + } + return self; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode_private.h b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode_private.h new file mode 100644 index 0000000..eb75fd4 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheInheritableSectionNode_private.h @@ -0,0 +1,65 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +@class GRMustacheTemplateAST; + +/** + * A GRMustacheInheritableSection is an AST node that represents inheritable + * sections as `{{$name}}...{{/name}}`. + */ +@interface GRMustacheInheritableSectionNode : NSObject { +@private + NSString *_name; + GRMustacheTemplateAST *_templateAST; +} + +/** + * The AST of the inner content of the section + * + * {{$ ... }} AST {{/ }} + */ +@property (nonatomic, retain, readonly) GRMustacheTemplateAST *templateAST GRMUSTACHE_API_INTERNAL; + +/** + * The name of the inheritable section: + * + * {{$ name }} ... {{/ }} + */ +@property (nonatomic, readonly) NSString *name GRMUSTACHE_API_INTERNAL; + +/** + * Returns a new inheritable section. + * + * @param name The name of the inheritable section + * @param templateAST The AST of the inner content of the section + * + * @return a new GRMustacheInheritableSection. + * + * @see GRMustacheTemplateASTNode + */ ++ (instancetype)inheritableSectionNodeWithName:(NSString *)name templateAST:(GRMustacheTemplateAST *)templateAST GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode.m b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode.m new file mode 100644 index 0000000..fe9963b --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode.m @@ -0,0 +1,85 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustachePartialNode_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + + +@implementation GRMustachePartialNode +@synthesize templateAST=_templateAST; +@synthesize name=_name; + +- (void)dealloc +{ + [_templateAST release]; + [_name release]; + [super dealloc]; +} + ++ (instancetype)partialNodeWithTemplateAST:(GRMustacheTemplateAST *)templateAST name:(NSString *)name +{ + return [[[self alloc] initWithTemplateAST:templateAST name:name] autorelease]; +} + +#pragma mark + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitPartialNode:self error:error]; +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + // Look for the last inheritable node in inner nodes. + // + // This allows a partial do define an inheritable section: + // + // { + // data: { }, + // expected: "partial1", + // name: "Partials in inheritable partials can override inheritable sections", + // template: "{{partial1}}{{/partial2}}" + // partials: { + // partial1: "{{$inheritable}}partial1{{/inheritable}}"; + // partial2: "{{$inheritable}}ignored{{/inheritable}}"; + // }, + // } + for (id innerASTNode in _templateAST.templateASTNodes) { + templateASTNode = [innerASTNode resolveTemplateASTNode:templateASTNode]; + } + return templateASTNode; +} + +#pragma mark - Private + +- (instancetype)initWithTemplateAST:(GRMustacheTemplateAST *)templateAST name:(NSString *)name +{ + self = [self init]; + if (self) { + _templateAST = [templateAST retain]; + _name = [name retain]; + } + return self; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode_private.h b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode_private.h new file mode 100644 index 0000000..7cff6cb --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustachePartialNode_private.h @@ -0,0 +1,59 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +@class GRMustacheTemplateAST; + +/** + * A GRMustachePartialNode is an AST node that represents partial tags as + * `{{>name}}`. + */ +@interface GRMustachePartialNode : NSObject { +@private + NSString *_name; + GRMustacheTemplateAST *_templateAST; +} + +/** + * The name of the partial: + * + * {{> name }} + */ +@property (nonatomic, retain, readonly) NSString *name GRMUSTACHE_API_INTERNAL; + +/** + * The abstract syntax tree of the partial template. + */ +@property (nonatomic, retain, readonly) GRMustacheTemplateAST *templateAST GRMUSTACHE_API_INTERNAL; + +/** + * Returns a newly created partial node. + * + * @param templateAST The abstract syntax tree of the partial template. + * @param name The name of the partial template. + * + * @return a newly created partial node. + */ ++ (instancetype)partialNodeWithTemplateAST:(GRMustacheTemplateAST *)templateAST name:(NSString *)name GRMUSTACHE_API_INTERNAL; +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag.m b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag.m new file mode 100644 index 0000000..082ac1f --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag.m @@ -0,0 +1,100 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheSectionTag_private.h" +#import "GRMustacheExpression_private.h" +#import "GRMustacheToken_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheRenderingEngine_private.h" + +@implementation GRMustacheSectionTag +@synthesize expression=_expression; +@synthesize templateAST=_templateAST; +@synthesize inverted=_inverted; + +- (void)dealloc +{ + [_expression release]; + [_templateString release]; + [_templateAST release]; + [super dealloc]; +} + ++ (instancetype)sectionTagWithExpression:(GRMustacheExpression *)expression inverted:(BOOL)inverted templateString:(NSString *)templateString innerRange:(NSRange)innerRange templateAST:(GRMustacheTemplateAST *)templateAST +{ + return [[[self alloc] initWithExpression:expression inverted:inverted templateString:templateString innerRange:innerRange templateAST:templateAST] autorelease]; +} + + +#pragma mark - GRMustacheTag + +- (NSString *)description +{ + GRMustacheToken *token = _expression.token; + if (token.templateID) { + return [NSString stringWithFormat:@"<%@ `%@` at line %lu of template %@>", [self class], token.templateSubstring, (unsigned long)token.line, token.templateID]; + } else { + return [NSString stringWithFormat:@"<%@ `%@` at line %lu>", [self class], token.templateSubstring, (unsigned long)token.line]; + } +} + +- (NSString *)innerTemplateString +{ + return [_templateString substringWithRange:_innerRange]; +} + +- (GRMustacheTagType)type +{ + return GRMustacheTagTypeSection; +} + +- (NSString *)renderContentWithContext:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + GRMustacheRenderingEngine *renderingEngine = [GRMustacheRenderingEngine renderingEngineWithContentType:_templateAST.contentType context:context]; + return [renderingEngine renderTemplateAST:_templateAST HTMLSafe:HTMLSafe error:error]; +} + + +#pragma mark - + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitSectionTag:self error:error]; +} + + +#pragma mark - Private + +- (instancetype)initWithExpression:(GRMustacheExpression *)expression inverted:(BOOL)inverted templateString:(NSString *)templateString innerRange:(NSRange)innerRange templateAST:(GRMustacheTemplateAST *)templateAST +{ + self = [super init]; + if (self) { + _expression = [expression retain]; + _inverted = inverted; + _templateString = [templateString retain]; + _innerRange = innerRange; + _templateAST = [templateAST retain]; + } + return self; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag_private.h b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag_private.h new file mode 100644 index 0000000..094e1ce --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheSectionTag_private.h @@ -0,0 +1,66 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheContentType.h" + +@class GRMustacheExpression; +@class GRMustacheTemplateAST; + +@interface GRMustacheSectionTag : GRMustacheTag { +@private + GRMustacheExpression *_expression; + BOOL _inverted; + NSString *_templateString; + NSRange _innerRange; + GRMustacheTemplateAST *_templateAST; +} + +@property (nonatomic, retain, readonly) GRMustacheExpression *expression GRMUSTACHE_API_INTERNAL; +@property (nonatomic, retain, readonly) GRMustacheTemplateAST *templateAST GRMUSTACHE_API_INTERNAL; + + +/** + * Builds a GRMustacheSectionTag. + * + * The rendering of Mustache sections depend on the value they are attached to. + * The value is fetched by evaluating the _expression_ parameter against a + * rendering context. + * + * The templateAST describes the inner content of the section + * + * @param expression The expression that would evaluate against a + * rendering context. + * @param inverted NO for {{# section }}, YES for {{^ section }}. + * @param templateString A Mustache template string. + * @param innerRange The range of the inner template string of the + * section in _templateString_. + * @param templateAST The AST of the inner content of the section. + * + * @return A GRMustacheSectionTag + * + * @see GRMustacheExpression + */ ++ (instancetype)sectionTagWithExpression:(GRMustacheExpression *)expression inverted:(BOOL)inverted templateString:(NSString *)templateString innerRange:(NSRange)innerRange templateAST:(GRMustacheTemplateAST *)templateAST GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.h b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.h new file mode 100644 index 0000000..cc67aa0 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.h @@ -0,0 +1,150 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" + +@class GRMustacheTemplateRepository; + +/** + * The types of Mustache tags + * + * @since v6.0 + */ +typedef NS_ENUM(NSUInteger, GRMustacheTagType) { + /** + * The type for variable tags such as `{{name}}`. + * + * @since v6.0 + */ + GRMustacheTagTypeVariable = 1 << 1 AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER, + + /** + * The type for regular and inverted section tags, such as + * `{{#name}}...{{/name}}` and `{{#name}}...{{/name}}`. + * + * @since v6.0 + */ + GRMustacheTagTypeSection = 1 << 2 AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER, + +} AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * The type for inverted section tags such as {{^ name }}...{{/}} + * + * This value is deprecated. + * + * @since v6.0 + * @deprecated v7.2 + */ +AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER_BUT_DEPRECATED_IN_GRMUSTACHE_VERSION_7_2 static GRMustacheTagType const GRMustacheTagTypeInvertedSection = 1 << 3; + +/** + * GRMustacheTag instances represent Mustache tags that render values, such as + * a variable tag `{{ name }}`, or a section tag `{{# name }}...{{/ })`. + * + * **Companion guides:** + * + * - https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * - https://github.com/groue/GRMustache/blob/master/Guides/rendering_objects.md + */ +@interface GRMustacheTag: NSObject + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Tag Information +//////////////////////////////////////////////////////////////////////////////// + + +/** + * The type of the tag + */ +@property (nonatomic, readonly) GRMustacheTagType type AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns the literal and unprocessed inner content of the tag. + * + * A section tag such as `{{# name }}inner content{{/}}` returns `inner content`. + * + * Variable tags such as `{{ name }}` have no inner content: their inner + * template string is the empty string. + */ +@property (nonatomic, readonly) NSString *innerTemplateString AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns the description of the tag. + * + * For example: + * + * ``` + * + * ``` + */ +- (NSString *)description; + +//////////////////////////////////////////////////////////////////////////////// +/// @name Methods Dedicated to the GRMustacheRendering Protocol +//////////////////////////////////////////////////////////////////////////////// + +/** + * This method is deprecated. + * + * Replace `[tag.templateRepository templateFromString:... error:...]` with + * `[GRMustacheTemplate templateFromString:... error:...]`. + * + * Replace `[tag.templateRepository templateNamed:... error:...]` with explicit + * invocation of the targeted template repository. + * + * @since v6.0 + * @deprecated v7.0 + */ +@property (nonatomic, readonly) GRMustacheTemplateRepository *templateRepository AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER_BUT_DEPRECATED; + +/** + * Returns the rendering of the tag's inner content, rendering all inner + * Mustache tags with the rendering context argument. + * + * This method is intended for objects conforming to the GRMustacheRendering + * protocol. The following Guides show some use cases for this method: + * + * - https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * - https://github.com/groue/GRMustache/blob/master/Guides/rendering_objects.md + * + * Note that variable tags such as `{{ name }}` have no inner content, and + * return the empty string. + * + * @param context A context for rendering inner tags. + * @param HTMLSafe Upon return contains YES or NO, depending on the content + * type of the tag's template, as set by the configuration of + * the source template repository. HTML templates yield YES, + * text templates yield NO. + * @param error If there is an error rendering the tag, upon return contains + * an NSError object that describes the problem. + * + * @see GRMustacheRendering + * @see GRMustacheContext + * + * @return The rendering of the tag's inner content. + */ +- (NSString *)renderContentWithContext:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.m b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.m new file mode 100644 index 0000000..8491c88 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag.m @@ -0,0 +1,72 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheTag_private.h" +#import "GRMustacheRendering_private.h" + +@implementation GRMustacheTag + +- (GRMustacheTagType)type +{ + [self doesNotRecognizeSelector:_cmd]; + return 0; +} + +- (GRMustacheTemplateRepository *)templateRepository +{ + return [GRMustacheRendering currentTemplateRepository]; +} + +- (NSString *)innerTemplateString +{ + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (NSString *)renderContentWithContext:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (BOOL)isInverted +{ + [self doesNotRecognizeSelector:_cmd]; + return NO; +} + +#pragma mark - + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + return templateASTNode; +} + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + [self doesNotRecognizeSelector:_cmd]; + return NO; +} + +@end + diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag_private.h b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag_private.h new file mode 100644 index 0000000..0485c73 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTag_private.h @@ -0,0 +1,56 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +@class GRMustacheContext; +@class GRMustacheTemplateRepository; + +// Documented in GRMustacheTag.h +typedef NS_ENUM(NSUInteger, GRMustacheTagType) { + GRMustacheTagTypeVariable = 1 << 1 GRMUSTACHE_API_PUBLIC, + GRMustacheTagTypeSection = 1 << 2 GRMUSTACHE_API_PUBLIC, +} GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheTag.h +@interface GRMustacheTag: NSObject + +// Documented in GRMustacheTag.h +@property (nonatomic, readonly) GRMustacheTagType type GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheTag.h +@property (nonatomic, readonly) NSString *innerTemplateString GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheTag.h +@property (nonatomic, readonly) GRMustacheTemplateRepository *templateRepository GRMUSTACHE_API_PUBLIC_BUT_DEPRECATED; + +// Documented in GRMustacheTag.h +- (NSString *)renderContentWithContext:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error GRMUSTACHE_API_PUBLIC; + +/** + * TODO + */ +@property (nonatomic, readonly, getter=isInverted) BOOL inverted GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateAST.m b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateAST.m new file mode 100644 index 0000000..5904da4 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateAST.m @@ -0,0 +1,76 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheTemplateASTNode_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + +@implementation GRMustacheTemplateAST +@synthesize templateASTNodes=_templateASTNodes; +@synthesize contentType=_contentType; + +- (void)dealloc +{ + [_templateASTNodes release]; + [super dealloc]; +} + ++ (instancetype)placeholderAST +{ + return [[[self alloc] initWithASTNodes:nil contentType:GRMustacheContentTypeHTML] autorelease]; +} + ++ (instancetype)templateASTWithASTNodes:(NSArray *)templateASTNodes contentType:(GRMustacheContentType)contentType +{ + NSAssert(templateASTNodes, @"nil templateASTNodes"); + return [[[self alloc] initWithASTNodes:templateASTNodes contentType:contentType] autorelease]; +} + +- (BOOL)isPlaceholder +{ + return (_templateASTNodes == nil); +} + +- (instancetype)initWithASTNodes:(NSArray *)templateASTNodes contentType:(GRMustacheContentType)contentType +{ + self = [super init]; + if (self) { + _templateASTNodes = [templateASTNodes retain]; + _contentType = contentType; + } + return self; +} + + +#pragma mark - + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitTemplateAST:self error:error]; +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + return templateASTNode; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTNode_private.h b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTNode_private.h new file mode 100644 index 0000000..b600cd0 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTNode_private.h @@ -0,0 +1,75 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + +@class GRMustacheExpression; + +/** + * The protocol for AST nodes. + * + * When parsing a Mustache template, GRMustacheCompiler builds an abstract + * tree of objects representing raw text and various mustache tags. + * + * This abstract tree is made of objects conforming to the + * GRMustacheTemplateASTNode protocol. + * + * For example, the template string "hello {{name}}!" would give four AST nodes: + * + * - a GRMustacheTextNode that renders "hello ". + * - a GRMustacheVariableTag that renders the value of the `name` key in the + * rendering context. + * - a GRMustacheTextNode that renders "!". + * - a GRMustachePartialNode that would contain the three previous nodes. + * + * @see GRMustacheCompiler + * @see GRMustacheContext + */ +@protocol GRMustacheTemplateASTNode +@required + +/** + * Has the visitor visit the receiver. + */ +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +/** + * In the context of template inheritance, return the AST node that should be + * rendered in lieu of the node argument. + * + * All classes conforming to the GRMustacheTemplateASTNode protocol return + * the node argument, but GRMustacheInheritableSectionNode and + * GRMustacheInheritablePartialNode. + * + * @param ASTNode A node + * + * @return The resolution of the node in the context of Mustache template + * inheritance. + * + * @see GRMustacheSectionTag + * @see GRMustacheTemplate + * @see GRMustacheInheritablePartialNode + */ +- (id)resolveTemplateASTNode:(id)templateASTNode GRMUSTACHE_API_INTERNAL; +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTVisitor_private.h b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTVisitor_private.h new file mode 100644 index 0000000..13e7976 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTemplateASTVisitor_private.h @@ -0,0 +1,45 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheTemplateAST; +@class GRMustacheInheritablePartialNode; +@class GRMustacheInheritableSectionNode; +@class GRMustachePartialNode; +@class GRMustacheVariableTag; +@class GRMustacheSectionTag; +@class GRMustacheTextNode; + +@protocol GRMustacheTemplateASTVisitor + +// Don't use these methods directly. Use -[ +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheContentType.h" +#import "GRMustacheTemplateASTVisitor_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +/** + * The GRMustacheTemplateAST represents the abstract syntax tree of a template. + */ +@interface GRMustacheTemplateAST : NSObject { +@private + NSArray *_templateASTNodes; + GRMustacheContentType _contentType; +} + +/** + * An NSArray containing instances + * + * @see GRMustacheTemplateASTNode + */ +@property (nonatomic, retain) NSArray *templateASTNodes GRMUSTACHE_API_INTERNAL; + +/** + * The content type of the AST + */ +@property (nonatomic) GRMustacheContentType contentType GRMUSTACHE_API_INTERNAL; + +/** + * Used by GRMustacheTemplateRepository, which uses placeholder ASTs when + * building recursive templates. + */ +@property (nonatomic, readonly, getter = isPlaceholder) BOOL placeholder GRMUSTACHE_API_INTERNAL; + +/** + * Returns a new allocated AST. + * + * @param templateASTNodes An array of instances. + * @param contentType A content type + * + * @return A new GRMustacheTemplateAST + * + * @see GRMustacheTemplateASTNode + */ ++ (instancetype)templateASTWithASTNodes:(NSArray *)templateASTNodes contentType:(GRMustacheContentType)contentType GRMUSTACHE_API_INTERNAL; + +/** + * Returns a placeholder AST + * @see placeholder + */ ++ (instancetype)placeholderAST GRMUSTACHE_API_INTERNAL; + +@end + diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode.m b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode.m new file mode 100644 index 0000000..52a0a36 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode.m @@ -0,0 +1,70 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheTextNode_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" + +@implementation GRMustacheTextNode + ++ (instancetype)textNodeWithText:(NSString *)text +{ + return [[[self alloc] initWithText:text] autorelease]; +} + +- (void)dealloc +{ + [_text release]; + [super dealloc]; +} + +- (NSString *)text +{ + return _text; +} + + +#pragma mark - + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitTextNode:self error:error]; +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + return templateASTNode; +} + + +#pragma mark - Private + +- (instancetype)initWithText:(NSString *)text +{ + NSAssert(text, @"WTF"); + self = [self init]; + if (self) { + _text = [text retain]; + } + return self; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode_private.h b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode_private.h new file mode 100644 index 0000000..7b226a5 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheTextNode_private.h @@ -0,0 +1,50 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTemplateASTNode_private.h" + +/** + * A GRMustacheTextNode is an AST node that represents raw text. + */ +@interface GRMustacheTextNode: NSObject { +@private + NSString *_text; +} + +/** + * The text of the text node. + */ +@property (nonatomic, retain, readonly) NSString *text GRMUSTACHE_API_INTERNAL; + +/** + * Builds and returns a GRMustacheTextNode. + * + * @param string The string that should be rendered. + * @return a GRMustacheTextNode + */ ++ (instancetype)textNodeWithText:(NSString *)string GRMUSTACHE_API_INTERNAL; + +@end + + diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag.m b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag.m new file mode 100644 index 0000000..bbe6ae1 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag.m @@ -0,0 +1,100 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheVariableTag_private.h" +#import "GRMustacheExpression_private.h" +#import "GRMustacheToken_private.h" + +@implementation GRMustacheVariableTag +@synthesize expression=_expression; +@synthesize escapesHTML=_escapesHTML; + +- (void)dealloc +{ + [_expression release]; + [super dealloc]; +} + ++ (instancetype)variableTagWithExpression:(GRMustacheExpression *)expression escapesHTML:(BOOL)escapesHTML contentType:(GRMustacheContentType)contentType +{ + return [[[self alloc] initWithExpression:expression escapesHTML:escapesHTML contentType:contentType] autorelease]; +} + + +#pragma mark - GRMustacheTag + +- (NSString *)description +{ + GRMustacheToken *token = _expression.token; + if (token.templateID) { + return [NSString stringWithFormat:@"<%@ `%@` at line %lu of template %@>", [self class], token.templateSubstring, (unsigned long)token.line, token.templateID]; + } else { + return [NSString stringWithFormat:@"<%@ `%@` at line %lu>", [self class], token.templateSubstring, (unsigned long)token.line]; + } +} + +- (GRMustacheTagType)type +{ + return GRMustacheTagTypeVariable; +} + +- (BOOL)isInverted +{ + return NO; +} + +- (NSString *)innerTemplateString +{ + return @""; +} + +- (NSString *)renderContentWithContext:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + if (HTMLSafe) { + *HTMLSafe = (_contentType == GRMustacheContentTypeHTML); + } + return @""; +} + + +#pragma mark - + +- (BOOL)acceptTemplateASTVisitor:(id)visitor error:(NSError **)error +{ + return [visitor visitVariableTag:self error:error]; +} + + +#pragma mark - Private + +- (instancetype)initWithExpression:(GRMustacheExpression *)expression escapesHTML:(BOOL)escapesHTML contentType:(GRMustacheContentType)contentType +{ + self = [super init]; + if (self) { + _expression = [expression retain]; + _escapesHTML = escapesHTML; + _contentType = contentType; + } + return self; +} + +@end diff --git a/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag_private.h b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag_private.h new file mode 100644 index 0000000..8d78038 --- /dev/null +++ b/Pods/GRMustache/src/classes/Compiling/TemplateAST/GRMustacheVariableTag_private.h @@ -0,0 +1,53 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheContentType.h" + +@class GRMustacheExpression; + +@interface GRMustacheVariableTag : GRMustacheTag { +@private + GRMustacheExpression *_expression; + BOOL _escapesHTML; + GRMustacheContentType _contentType; +} + +@property (nonatomic, retain, readonly) GRMustacheExpression *expression GRMUSTACHE_API_INTERNAL; +@property (nonatomic, readonly) BOOL escapesHTML GRMUSTACHE_API_INTERNAL; + +/** + * Builds and returns a GRMustacheVariableTag. + * + * @param expression The expression that would evaluate against a rendering + * contex. + * @param escapesHTML YES if the value should be escaped. + * @param contentType The content type of the tag rendering. + * + * @return a GRMustacheVariableTag + * + * @see GRMustacheExpression + */ ++ (instancetype)variableTagWithExpression:(GRMustacheExpression *)expression escapesHTML:(BOOL)escapesHTML contentType:(GRMustacheContentType)contentType GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.h b/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.h new file mode 100644 index 0000000..2d061ae --- /dev/null +++ b/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.h @@ -0,0 +1,296 @@ +// The MIT License +// +// Copyright (c) 2013 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" +#import "GRMustacheContentType.h" + +@class GRMustacheContext; +@protocol GRMustacheTagDelegate; + +/** + * A GRMustacheConfiguration instance configures GRMustache rendering. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/configuration.md + * + * The default configuration [GRMustacheConfiguration defaultConfiguration] + * applies to all GRMustache rendering by default: + * + * ``` + * // Have GRMustache templates render text by default, + * // and do not HTML-escape their input. + * [GRMustacheConfiguration defaultConfiguration].contentType = GRMustacheContentTypeText; + * ``` + * + * You can also alter the configuration of a specific template repository: its + * configuration only applies to the templates built by this very template + * repository: + * + * ``` + * // All templates loaded from _repo_ will use [[ and ]] as tag delimiters. + * GRMustacheTemplateRepository *repo = [GRMustacheTemplateRepository templateRepositoryWithBundle:nil]; + * repo.configuration.tagStartDelimiter = @"[["; + * repo.configuration.tagEndDelimiter = @"]]"; + * ``` + * + * A third option is to create a new configuration, and assign it to the template: + * + * ``` + * // Create a configuration + * GRMustacheConfiguration *configuration = [GRMustacheConfiguration configuration]; + * configuration.... // setup + * + * GRMustacheTemplateRepository *repo = [GRMustacheTemplateRepository templateRepositoryWithBundle:nil]; + * repo.configuration = configuration; + * ``` + * + * The `contentType` option can be specified at the template level, so that your + * repositories can mix HTML and text templates: see the documentation of this + * property. + * + * The `tagStartDelimiter` and `tagEndDelimiter` options can also be specified + * at the template level, using a "Set Delimiters tag": see the documentation of + * these properties. + * + * @see GRMustacheTemplateRepository + * + * @since v6.2 + */ +@interface GRMustacheConfiguration : NSObject { +@private + GRMustacheContentType _contentType; + NSString *_tagStartDelimiter; + NSString *_tagEndDelimiter; + GRMustacheContext *_baseContext; + BOOL _locked; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Default Configuration +//////////////////////////////////////////////////////////////////////////////// + + +/** + * The default configuration. + * + * All templates and template repositories use the default configuration unless + * you specify otherwise by setting the configuration of a template repository. + * + * The "default" defaultConfiguration has GRMustacheContentTypeHTML contentType, + * and {{ and }} as tag delimiters. + * + * @returns The default configuration. + * + * @since v6.2 + */ ++ (GRMustacheConfiguration *)defaultConfiguration AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Creating Configuration +//////////////////////////////////////////////////////////////////////////////// + + +/** + * @returns A new factory configuration. + * + * Its contentType is GRMustacheContentTypeHTML. + * Its tag delimiters are {{ and }}. + * + * @since v6.2 + */ ++ (GRMustacheConfiguration *)configuration AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Set Up Configuration +//////////////////////////////////////////////////////////////////////////////// + + +/** + * The base context for templates rendering. The default base context contains + * the GRMustache standard Library. + * + * @see GRMustacheTemplate + * + * @since v6.4 + */ +@property (nonatomic, retain) GRMustacheContext *baseContext AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Extends the base context of the receiver with the provided object, making its + * keys available for all renderings. + * + * For example: + * + * ``` + * GRMustacheConfiguration *configuration = [GRMustacheConfiguration defaultConfiguration]; + * + * // Have the `name` key defined for all template renderings: + * id object = @{ @"name": @"Arthur" }; + * [configuration extendBaseContextWithObject:object]; + * + * // Renders "Arthur" + * [GRMustacheTemplate renderObject:nil fromString:@"{{name}}" error:NULL]; + * ``` + * + * Keys defined by _object_ can be overriden by other objects that will + * eventually enter the context stack: + * + * ``` + * // Renders "Billy", not "Arthur" + * [GRMustacheTemplate renderObject:nil:@{ @"name": @"Billy" } fromString:@"{{name}}" error:NULL]; + * ``` + * + * This method is a shortcut. It is equivalent to the following line of code: + * + * ``` + * configuration.baseContext = [configuration.baseContext contextByAddingObject:object]; + * ``` + * + * @param object An object + * + * @see baseContext + * @see extendBaseContextWithProtectedObject: + * @see extendBaseContextWithTagDelegate: + * + * @since v6.8 + */ +- (void)extendBaseContextWithObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Extends the base context of the receiver with the provided object, making its + * keys available for all renderings. + * + * Keys defined by _object_ are given priority, which means that they can not be + * overriden by other objects that will eventually enter the context stack. + * + * For example: + * + * ``` + * GRMustacheConfiguration *configuration = [GRMustacheConfiguration defaultConfiguration]; + * + * // The `precious` key is given priority: + * [configuration extendBaseContextWithProtectedObject:@{ @"precious": @"gold" }]; + * + * // Renders "gold", not "lead". + * [GRMustacheTemplate renderObject:nil:@{ @"precious": @"lead" } fromString:@"{{precious}}" error:NULL]; + * ``` + * + * This method is a shortcut. It is equivalent to the following line of code: + * + * ``` + * configuration.baseContext = [configuration.baseContext contextByAddingProtectedObject:object]; + * ``` + * + * @param object An object + * + * @see baseContext + * @see extendBaseContextWithObject: + * @see extendBaseContextWithTagDelegate: + * + * @since v6.8 + */ +- (void)extendBaseContextWithProtectedObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER;; + +/** + * Extends the base context of the receiver with a tag delegate, making it aware + * of the rendering of all template tags. + * + * This method is a shortcut. It is equivalent to the following line of code: + * + * ``` + * configuration.baseContext = [configuration.baseContext contextByAddingTagDelegate:tagDelegate]; + * ``` + * + * @param tagDelegate A tag delegate + * + * @see baseContext + * @see extendBaseContextWithObject: + * @see extendBaseContextWithProtectedObject: + * + * @since v6.8 + */ +- (void)extendBaseContextWithTagDelegate:(id)tagDelegate AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER;; + +/** + * The content type of strings rendered by templates. + * + * This property affects the HTML-escaping of your data, and the inclusion + * of templates in other templates. + * + * The `GRMustacheContentTypeHTML` content type has templates render HTML. + * This is the default behavior. HTML template escape the input of variable tags + * such as `{{name}}`. Use triple mustache tags `{{{content}}}` in order to + * avoid the HTML-escaping. + * + * The `GRMustacheContentTypeText` content type has templates render text. + * They do not HTML-escape their input: `{{name}}` and `{{{name}}}` have + * identical renderings. + * + * GRMustache safely keeps track of the content type of templates: should a HTML + * template embed a text template, the content of the text template would be + * HTML-escaped. + * + * There is no API to specify the content type of individual templates. However, + * you can use pragma tags right in the content of your templates: + * + * - `{{% CONTENT_TYPE:TEXT }}` turns a template into a text template. + * - `{{% CONTENT_TYPE:HTML }}` turns a template into a HTML template. + * + * Insert those pragma tags early in your templates. For example: + * + * ``` + * {{! This template renders a bash script. }} + * {{% CONTENT_TYPE:TEXT }} + * export LANG={{ENV.LANG}} + * ... + * ``` + * + * Should two such pragmas be found in a template content, the last one wins. + * + * @since v6.2 + */ +@property (nonatomic) GRMustacheContentType contentType AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * The opening delimiter for Mustache tags. Its default value is `{{`. + * + * You can also change the delimiters right in your templates using a "Set + * Delimiter tag": {{=[[ ]]=}} changes start and end delimiters to [[ and ]]. + * + * @since v6.4 + */ +@property (nonatomic, copy) NSString *tagStartDelimiter AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * The closing delimiter for Mustache tags. Its default value is `}}`. + * + * You can also change the delimiters right in your templates using a "Set + * Delimiter tag": {{=[[ ]]=}} changes start and end delimiters to [[ and ]]. + * + * @since v6.4 + */ +@property (nonatomic, copy) NSString *tagEndDelimiter AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end diff --git a/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.m b/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.m new file mode 100644 index 0000000..0f09254 --- /dev/null +++ b/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration.m @@ -0,0 +1,165 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheConfiguration_private.h" +#import "GRMustache_private.h" +#import "GRMustacheContext_private.h" + +@implementation GRMustacheConfiguration +@synthesize contentType=_contentType; +@synthesize tagStartDelimiter=_tagStartDelimiter; +@synthesize tagEndDelimiter=_tagEndDelimiter; +@synthesize baseContext=_baseContext; +@synthesize locked=_locked; + ++ (GRMustacheConfiguration *)defaultConfiguration +{ + static GRMustacheConfiguration *defaultConfiguration; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + defaultConfiguration = [[GRMustacheConfiguration alloc] init]; + }); + return defaultConfiguration; +} + ++ (GRMustacheConfiguration *)configuration +{ + return [[[GRMustacheConfiguration alloc] init] autorelease]; +} + +- (void)dealloc +{ + [_tagStartDelimiter release]; + [_tagEndDelimiter release]; + [_baseContext release]; + [super dealloc]; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _contentType = GRMustacheContentTypeHTML; + _tagStartDelimiter = [@"{{" retain]; // useless retain that matches the release in dealloc + _tagEndDelimiter = [@"}}" retain]; // useless retain that matches the release in dealloc + _baseContext = [[GRMustacheContext contextWithObject:[GRMustache standardLibrary]] retain]; + } + return self; +} + +- (void)lock +{ + _locked = YES; +} + +- (void)setContentType:(GRMustacheContentType)contentType +{ + [self assertNotLocked]; + + _contentType = contentType; +} + +- (void)setTagStartDelimiter:(NSString *)tagStartDelimiter +{ + [self assertNotLocked]; + + if (tagStartDelimiter.length == 0) { + [NSException raise:NSInvalidArgumentException format:@"Invalid tagStartDelimiter:%@", tagStartDelimiter]; + return; + } + + if (_tagStartDelimiter != tagStartDelimiter) { + [_tagStartDelimiter release]; + _tagStartDelimiter = [tagStartDelimiter copy]; + } +} + +- (void)setTagEndDelimiter:(NSString *)tagEndDelimiter +{ + [self assertNotLocked]; + + if (tagEndDelimiter.length == 0) { + [NSException raise:NSInvalidArgumentException format:@"Invalid tagEndDelimiter:%@", tagEndDelimiter]; + return; + } + + if (_tagEndDelimiter != tagEndDelimiter) { + [_tagEndDelimiter release]; + _tagEndDelimiter = [tagEndDelimiter copy]; + } +} + +- (void)setBaseContext:(GRMustacheContext *)baseContext +{ + [self assertNotLocked]; + + if (!baseContext) { + [NSException raise:NSInvalidArgumentException format:@"Invalid baseContext:nil"]; + return; + } + + if (_baseContext != baseContext) { + [_baseContext release]; + _baseContext = [baseContext retain]; + } +} + +- (void)extendBaseContextWithObject:(id)object +{ + self.baseContext = [self.baseContext contextByAddingObject:object]; +} + +- (void)extendBaseContextWithProtectedObject:(id)object +{ + self.baseContext = [self.baseContext contextByAddingProtectedObject:object]; +} + +- (void)extendBaseContextWithTagDelegate:(id)tagDelegate +{ + self.baseContext = [self.baseContext contextByAddingTagDelegate:tagDelegate]; +} + + +#pragma mark - + +- (id)copyWithZone:(NSZone *)zone +{ + GRMustacheConfiguration *configuration = [[GRMustacheConfiguration alloc] init]; + configuration.contentType = _contentType; + configuration.tagStartDelimiter = _tagStartDelimiter; + configuration.tagEndDelimiter = _tagEndDelimiter; + configuration.baseContext = _baseContext; + // Do not copy the _locked flag, so that the copy is mutable. + return configuration; +} + + +#pragma mark - Private + +- (void)assertNotLocked +{ + if (_locked) { + [NSException raise:NSGenericException format:@"%@ was mutated after template compilation", self]; + } +} + +@end diff --git a/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration_private.h b/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration_private.h new file mode 100644 index 0000000..e2c155b --- /dev/null +++ b/Pods/GRMustache/src/classes/Configuration/GRMustacheConfiguration_private.h @@ -0,0 +1,88 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheContentType.h" + +@class GRMustacheContext; +@protocol GRMustacheTagDelegate; + +// Documented in GRMustacheConfiguration.h +@interface GRMustacheConfiguration : NSObject { +@private + GRMustacheContentType _contentType; + NSString *_tagStartDelimiter; + NSString *_tagEndDelimiter; + GRMustacheContext *_baseContext; + BOOL _locked; +} + + +// Documented in GRMustacheConfiguration.h ++ (GRMustacheConfiguration *)defaultConfiguration GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h ++ (GRMustacheConfiguration *)configuration GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +@property (nonatomic) GRMustacheContentType contentType GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +@property (nonatomic, copy) NSString *tagStartDelimiter GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +@property (nonatomic, copy) NSString *tagEndDelimiter GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +@property (nonatomic, retain) GRMustacheContext *baseContext GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +- (void)extendBaseContextWithObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +- (void)extendBaseContextWithProtectedObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheConfiguration.h +- (void)extendBaseContextWithTagDelegate:(id)tagDelegate GRMUSTACHE_API_PUBLIC; + +/** + * Whether the receiver is locked or not. + * + * @see lock + */ +@property (nonatomic, getter = isLocked, readonly) BOOL locked GRMUSTACHE_API_INTERNAL; + +/** + * Locks the receiver. + * + * A locked configuration raises an exception when the user attempts to mutate + * it. It is in effect an immutable object. + * + * The goal is to prevent the user to build template and alter the configuration + * afterwards. + * + * @see locked + */ +- (void)lock GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/GRMustache.h b/Pods/GRMustache/src/classes/GRMustache.h new file mode 100644 index 0000000..df385a1 --- /dev/null +++ b/Pods/GRMustache/src/classes/GRMustache.h @@ -0,0 +1,174 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" + +@protocol GRMustacheRendering; +@class GRMustacheTag; +@class GRMustacheContext; + +/** + * A C struct that hold GRMustache version information + * + * @since v1.0 + */ +typedef struct { + int major; /**< The major component of the version. */ + int minor; /**< The minor component of the version. */ + int patch; /**< The patch-level component of the version. */ +} GRMustacheVersion; + + +/** + * The GRMustache class provides with global-level information and configuration + * of the GRMustache library. + * + * @since v1.0 + */ +@interface GRMustache: NSObject + +//////////////////////////////////////////////////////////////////////////////// +/// @name Getting the GRMustache version +//////////////////////////////////////////////////////////////////////////////// + +/** + * @return The version of GRMustache as a GRMustacheVersion struct. + * + * @since v7.0 + */ ++ (GRMustacheVersion)libraryVersion AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Preventing NSUndefinedKeyException in Development configuration +//////////////////////////////////////////////////////////////////////////////// + +/** + * Have GRMustache avoid most `NSUndefinedKeyExceptions` when rendering + * templates. + * + * The rendering of a GRMustache template can lead to `NSUndefinedKeyExceptions` + * to be raised, because of the usage of the `valueForKey:` method. Those + * exceptions are nicely handled by GRMustache, and are part of the regular + * rendering of a template. + * + * Unfortunately, Objective-C exceptions have several drawbacks, particularly: + * + * 1. they play badly with autorelease pools, and are reputed to leak memory. + * 2. they usually stop your debugger when you are developping your application. + * + * The first point is indeed a matter of worry: Apple does not guarantee that + * exceptions raised by `valueForKey:` do not leak memory. However, I never had + * any evidence of such a leak from NSObject's implementation. + * + * Should you still worry, we recommend that you avoid the `valueForKey:` method + * altogether. Instead, implement the [keyed subscripting](http://clang.llvm.org/docs/ObjectiveCLiterals.html#dictionary-style-subscripting) + * `objectForKeyedSubscript:` method on objects that you provide to GRMustache. + * + * The second point is valid also: NSUndefinedKeyException raised by template + * rendering may become a real annoyance when you are debugging your project, + * because it's likely you've told your debugger to stop on every Objective-C + * exceptions. + * + * You can avoid them as well: make sure you invoke once, early in your + * application, the `preventNSUndefinedKeyExceptionAttack` method. + * + * Depending on the number of NSUndefinedKeyException that get prevented, you + * will experience a slight performance hit, or a performance improvement. + * + * Since the main use case for this method is to avoid Xcode breaks on rendering + * exceptions, the best practice is to conditionally invoke this method, using + * the [NS_BLOCK_ASSERTIONS](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html) + * that helps identifying the Debug configuration of your targets: + * + * ``` + * #if !defined(NS_BLOCK_ASSERTIONS) + * // Debug configuration: keep GRMustache quiet + * [GRMustache preventNSUndefinedKeyExceptionAttack]; + * #endif + * ``` + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/runtime.md + * + * @since v1.7 + */ ++ (void)preventNSUndefinedKeyExceptionAttack AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Standard Library +//////////////////////////////////////////////////////////////////////////////// + +/** + * @return The GRMustache standard library. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/standard_library.md + * + * @since v6.4 + */ ++ (NSObject *)standardLibrary AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Building rendering objects +//////////////////////////////////////////////////////////////////////////////// + +/** + * This method is deprecated. Use + * `+[GRMustacheRendering renderingObjectForObject:]` instead. + * + * @see GRMustacheRendering class + * + * @since v6.0 + * @deprecated v7.0 + */ ++ (id)renderingObjectForObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER_BUT_DEPRECATED; + +/** + * This method is deprecated. Use + * `+[GRMustacheRendering renderingObjectWithBlock:]` instead. + * + * @see GRMustacheRendering class + * + * @since v6.0 + * @deprecated v7.0 + */ ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))block AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER_BUT_DEPRECATED; + +@end + +#import "GRMustacheTemplate.h" +#import "GRMustacheTagDelegate.h" +#import "GRMustacheTemplateRepository.h" +#import "GRMustacheFilter.h" +#import "GRMustacheError.h" +#import "GRMustacheVersion.h" +#import "GRMustacheContentType.h" +#import "GRMustacheContext.h" +#import "GRMustacheRendering.h" +#import "GRMustacheTag.h" +#import "GRMustacheConfiguration.h" +#import "GRMustacheLocalizer.h" +#import "GRMustacheSafeKeyAccess.h" +#import "NSValueTransformer+GRMustache.h" +#import "NSFormatter+GRMustache.h" diff --git a/Pods/GRMustache/src/classes/GRMustache.m b/Pods/GRMustache/src/classes/GRMustache.m new file mode 100644 index 0000000..6e6ed18 --- /dev/null +++ b/Pods/GRMustache/src/classes/GRMustache.m @@ -0,0 +1,120 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustache_private.h" +#import "GRMustacheKeyAccess_private.h" +#import "GRMustacheVersion.h" +#import "GRMustacheRendering_private.h" +#import "GRMustacheStandardLibrary_private.h" +#import "GRMustacheJavascriptLibrary_private.h" +#import "GRMustacheHTMLLibrary_private.h" +#import "GRMustacheURLLibrary_private.h" +#import "GRMustacheEachFilter_private.h" +#import "GRMustacheLocalizer.h" + + +// ============================================================================= +#pragma mark - GRMustache + +@implementation GRMustache + +// ============================================================================= +#pragma mark - Global services + ++ (void)preventNSUndefinedKeyExceptionAttack +{ + [GRMustacheKeyAccess preventNSUndefinedKeyExceptionAttack]; +} + ++ (GRMustacheVersion)libraryVersion +{ + return (GRMustacheVersion){ + .major = GRMUSTACHE_MAJOR_VERSION, + .minor = GRMUSTACHE_MINOR_VERSION, + .patch = GRMUSTACHE_PATCH_VERSION }; +} + ++ (NSObject *)standardLibrary +{ + static NSObject *standardLibrary = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + standardLibrary = [[NSDictionary dictionaryWithObjectsAndKeys: + // {{ capitalized(value) }} + [[[GRMustacheCapitalizedFilter alloc] init] autorelease], @"capitalized", + + // {{ lowercase(value) }} + [[[GRMustacheLowercaseFilter alloc] init] autorelease], @"lowercase", + + // {{ uppercase(value) }} + [[[GRMustacheUppercaseFilter alloc] init] autorelease], @"uppercase", + + // {{# isBlank(value) }}...{{/}} + [[[GRMustacheBlankFilter alloc] init] autorelease], @"isBlank", + + // {{# isEmpty(value) }}...{{/}} + [[[GRMustacheEmptyFilter alloc] init] autorelease], @"isEmpty", + + // {{ localize(value) }} + // {{# localize }}...{{/}} + [[[GRMustacheLocalizer alloc] initWithBundle:nil tableName:nil] autorelease], @"localize", + + // {{# each(collection) }}...{{/}} + [[[GRMustacheEachFilter alloc] init] autorelease], @"each", + + [NSDictionary dictionaryWithObjectsAndKeys: + + // {{ HTML.escape(value) }} + // {{# HTML.escape }}...{{/}} + [[[GRMustacheHTMLEscapeFilter alloc] init] autorelease], @"escape", + nil], @"HTML", + + [NSDictionary dictionaryWithObjectsAndKeys: + + // {{ javascript.escape(value) }} + // {{# javascript.escape }}...{{/}} + [[[GRMustacheJavascriptEscaper alloc] init] autorelease], @"escape", + nil], @"javascript", + + [NSDictionary dictionaryWithObjectsAndKeys: + + // {{ URL.escape(value) }} + // {{# URL.escape }}...{{/}} + [[[GRMustacheURLEscapeFilter alloc] init] autorelease], @"escape", + nil], @"URL", + nil] retain]; + }); + + return standardLibrary; +} + ++ (id)renderingObjectForObject:(id)object +{ + return [GRMustacheRendering renderingObjectForObject:object]; +} + ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))block +{ + return [GRMustacheRendering renderingObjectWithBlock:block]; +} + +@end diff --git a/Pods/GRMustache/src/classes/GRMustacheVersion.h b/Pods/GRMustache/src/classes/GRMustacheVersion.h new file mode 100644 index 0000000..c711cea --- /dev/null +++ b/Pods/GRMustache/src/classes/GRMustacheVersion.h @@ -0,0 +1,44 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +/** + * The major component of GRMustache version + * + * @since v1.0 + */ +#define GRMUSTACHE_MAJOR_VERSION 7 + +/** + * The minor component of GRMustache version + * + * @since v1.0 + */ +#define GRMUSTACHE_MINOR_VERSION 3 + +/** + * The patch-level component of GRMustache version + * + * @since v1.0 + */ +#define GRMUSTACHE_PATCH_VERSION 0 + diff --git a/Pods/GRMustache/src/classes/GRMustache_private.h b/Pods/GRMustache/src/classes/GRMustache_private.h new file mode 100644 index 0000000..051e417 --- /dev/null +++ b/Pods/GRMustache/src/classes/GRMustache_private.h @@ -0,0 +1,54 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@protocol GRMustacheRendering; +@class GRMustacheTag; +@class GRMustacheContext; + +// Documented in GRMustache.h +typedef struct { + int major; + int minor; + int patch; +} GRMustacheVersion; + +@interface GRMustache: NSObject + +// Documented in GRMustache.h ++ (GRMustacheVersion)libraryVersion GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustache.h ++ (void)preventNSUndefinedKeyExceptionAttack GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustache.h ++ (NSObject *)standardLibrary GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustache.h ++ (id)renderingObjectForObject:(id)object GRMUSTACHE_API_PUBLIC_BUT_DEPRECATED; + +// Documented in GRMustache.h ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))block GRMUSTACHE_API_PUBLIC_BUT_DEPRECATED; + +@end diff --git a/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser.m b/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser.m new file mode 100644 index 0000000..0a8d0e1 --- /dev/null +++ b/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser.m @@ -0,0 +1,561 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpressionParser_private.h" +#import "GRMustacheImplicitIteratorExpression_private.h" +#import "GRMustacheFilteredExpression_private.h" +#import "GRMustacheIdentifierExpression_private.h" +#import "GRMustacheScopedExpression_private.h" +#import "GRMustacheError.h" + +@implementation GRMustacheExpressionParser + +- (GRMustacheExpression *)parseExpression:(NSString *)string empty:(BOOL *)empty error:(NSError **)error +{ + // -> ;;sm_parenLevel=0 -> stateInitial + // stateInitial -> ' ' -> stateInitial + // stateInitial -> '.' -> stateLeadingDot + // stateInitial -> 'a' -> stateIdentifier + // stateInitial -> sm_parenLevel==0;EOF; -> stateEmpty + // stateLeadingDot -> 'a' -> stateIdentifier + // stateLeadingDot -> ' ' -> stateIdentifierDone + // stateIdentifier -> '(';++sm_parenLevel -> stateInitial + // stateLeadingDot -> sm_parenLevel>0;')';--sm_parenLevel -> stateFilterDone + // stateLeadingDot -> sm_parenLevel==0;EOF; -> stateValid + // stateIdentifier -> 'a' -> stateIdentifier + // stateIdentifier -> '.' -> stateWaitingForIdentifier + // stateIdentifier -> ' ' -> stateIdentifierDone + // stateIdentifier -> '(';++sm_parenLevel -> stateInitial + // stateIdentifier -> sm_parenLevel>0;')';--sm_parenLevel -> stateFilterDone + // stateIdentifier -> sm_parenLevel==0;EOF; -> stateValid + // stateWaitingForIdentifier -> 'a' -> stateIdentifier + // stateIdentifierDone -> ' ' -> stateIdentifierDone + // stateIdentifierDone -> sm_parenLevel==0;EOF; -> stateValid + // stateIdentifierDone -> '(';++sm_parenLevel -> stateInitial + // stateFilterDone -> ' ' -> stateFilterDone + // stateFilterDone -> '.' -> stateWaitingForIdentifier + // stateFilterDone -> '(';++sm_parenLevel -> stateInitial + // stateFilterDone -> sm_parenLevel==0;EOF; -> stateValid + // stateFilterDone -> sm_parenLevel>0;')';--sm_parenLevel -> stateFilterDone + + // state machine internal states + enum { + stateInitial, + stateLeadingDot, + stateIdentifier, + stateWaitingForIdentifier, + stateIdentifierDone, + stateFilterDone, + stateEmpty, + stateError, + stateValid + } state = stateInitial; + NSUInteger identifierStart = NSNotFound; + NSMutableArray *filterExpressionStack = [NSMutableArray array]; + GRMustacheExpression *currentExpression=nil; + GRMustacheExpression *validExpression=nil; + + NSUInteger length = string.length; + for (NSUInteger i = 0; i < length; ++i) { + + // shortcut + if (state == stateError) { + break; + } + + unichar c = [string characterAtIndex:i]; + switch (state) { + case stateInitial: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + break; + + case '.': + NSAssert(currentExpression == nil, @"WTF expected nil currentExpression"); + state = stateLeadingDot; + currentExpression = [GRMustacheImplicitIteratorExpression expression]; + break; + + case '(': + state = stateError; + break; + + case ')': + state = stateError; + break; + + case ',': + state = stateError; + break; + + case '{': + case '}': + case '&': + case '$': + case '#': + case '^': + case '/': + case '<': + case '>': + // invalid as an identifier start + state = stateError; + break; + + default: + state = stateIdentifier; + + // enter stateIdentifier + identifierStart = i; + break; + } + break; + + case stateLeadingDot: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + state = stateIdentifierDone; + break; + + case '.': + state = stateError; + break; + + case '(': { + NSAssert(currentExpression, @"WTF expected currentExpression"); + state = stateInitial; + [filterExpressionStack addObject:currentExpression]; + currentExpression = nil; + } break; + + case ')': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + + state = stateFilterDone; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + currentExpression = [GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:NO]; + } else { + state = stateError; + } + break; + + case ',': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + + state = stateInitial; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + [filterExpressionStack addObject:[GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:YES]]; + currentExpression = nil; + } else { + state = stateError; + } + break; + + case '{': + case '}': + case '&': + case '$': + case '#': + case '^': + case '/': + case '<': + case '>': + // invalid as an identifier start + state = stateError; + break; + + default: + state = stateIdentifier; + + // enter stateIdentifier + identifierStart = i; + break; + } + break; + + case stateIdentifier: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': { + // leave stateIdentifier + NSString *identifier = [string substringWithRange:(NSRange){ .location = identifierStart, .length = i - identifierStart }]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + state = stateIdentifierDone; + } break; + + case '.': { + // leave stateIdentifier + NSString *identifier = [string substringWithRange:(NSRange){ .location = identifierStart, .length = i - identifierStart }]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + state = stateWaitingForIdentifier; + } break; + + case '(': { + // leave stateIdentifier + NSString *identifier = [string substringWithRange:(NSRange){ .location = identifierStart, .length = i - identifierStart }]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + NSAssert(currentExpression, @"WTF expected currentExpression"); + state = stateInitial; + [filterExpressionStack addObject:currentExpression]; + currentExpression = nil; + } break; + + case ')': { + // leave stateIdentifier + NSString *identifier = [string substringWithRange:(NSRange){ .location = identifierStart, .length = i - identifierStart }]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateFilterDone; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + currentExpression = [GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:NO]; + } else { + state = stateError; + } + } break; + + case ',': { + // leave stateIdentifier + NSString *identifier = [string substringWithRange:(NSRange){ .location = identifierStart, .length = i - identifierStart }]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateInitial; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + [filterExpressionStack addObject:[GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:YES]]; + currentExpression = nil; + } else { + state = stateError; + } + } break; + + + default: + break; + } + break; + + case stateWaitingForIdentifier: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + state = stateError; + break; + + case '.': + state = stateError; + break; + + case '(': + state = stateError; + break; + + case ')': + state = stateError; + break; + + case ',': + state = stateError; + break; + + case '{': + case '}': + case '&': + case '$': + case '#': + case '^': + case '/': + case '<': + case '>': + // invalid as an identifier start + state = stateError; + break; + + default: + state = stateIdentifier; + + // enter stateIdentifier + identifierStart = i; + break; + } + break; + + case stateIdentifierDone: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + break; + + case '.': + state = stateError; + break; + + case '(': + NSAssert(currentExpression, @"WTF expected currentExpression"); + state = stateInitial; + [filterExpressionStack addObject:currentExpression]; + currentExpression = nil; + break; + + case ')': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateFilterDone; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + currentExpression = [GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:NO]; + } else { + state = stateError; + } + break; + + case ',': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateInitial; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + [filterExpressionStack addObject:[GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:YES]]; + currentExpression = nil; + } else { + state = stateError; + } + break; + + default: + state = stateError; + break; + } + break; + + case stateFilterDone: + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + break; + + case '.': + state = stateWaitingForIdentifier; + break; + + case '(': + NSAssert(currentExpression, @"WTF expected currentExpression"); + state = stateInitial; + [filterExpressionStack addObject:currentExpression]; + currentExpression = nil; + break; + + case ')': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateFilterDone; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + currentExpression = [GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:NO]; + } else { + state = stateError; + } + break; + + case ',': + if (filterExpressionStack.count > 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + NSAssert(filterExpressionStack.count > 0, @"WTF expected non empty filterExpressionStack"); + state = stateInitial; + GRMustacheExpression *filterExpression = [filterExpressionStack lastObject]; + [filterExpressionStack removeLastObject]; + [filterExpressionStack addObject:[GRMustacheFilteredExpression expressionWithFilterExpression:filterExpression argumentExpression:currentExpression curried:YES]]; + currentExpression = nil; + } else { + state = stateError; + } + break; + + default: + state = stateError; + break; + } + break; + default: + NSAssert(NO, @"WTF unexpected state"); + break; + } + } + + + // EOF + + switch (state) { + case stateInitial: + if (filterExpressionStack.count == 0) { + state = stateEmpty; + } else { + state = stateError; + } + break; + + case stateLeadingDot: + if (filterExpressionStack.count == 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + validExpression = currentExpression; + state = stateValid; + } else { + state = stateError; + } + break; + + case stateIdentifier: { + // leave stateIdentifier + NSString *identifier = [string substringFromIndex:identifierStart]; + if (currentExpression) { + currentExpression = [GRMustacheScopedExpression expressionWithBaseExpression:currentExpression identifier:identifier]; + } else { + currentExpression = [GRMustacheIdentifierExpression expressionWithIdentifier:identifier]; + } + + if (filterExpressionStack.count == 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + validExpression = currentExpression; + state = stateValid; + } else { + state = stateError; + } + } break; + + case stateWaitingForIdentifier: + state = stateError; + break; + + case stateIdentifierDone: + if (filterExpressionStack.count == 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + validExpression = currentExpression; + state = stateValid; + } else { + state = stateError; + } + break; + + case stateFilterDone: + if (filterExpressionStack.count == 0) { + NSAssert(currentExpression, @"WTF expected currentExpression"); + validExpression = currentExpression; + state = stateValid; + } else { + state = stateError; + } + break; + + case stateError: + break; + + default: + NSAssert(NO, @"WTF unexpected state"); + break; + } + + + // End + + switch (state) { + case stateEmpty: + if (empty != NULL) { + *empty = YES; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeParseError userInfo:[NSDictionary dictionaryWithObject:@"Missing expression" forKey:NSLocalizedDescriptionKey]]; + } + return nil; + + case stateError: + if (empty != NULL) { + *empty = NO; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeParseError userInfo:[NSDictionary dictionaryWithObject:@"Invalid expression" forKey:NSLocalizedDescriptionKey]]; + } + return nil; + + case stateValid: + NSAssert(validExpression, @"WTF expected validExpression"); + return validExpression; + + default: + NSAssert(NO, @"WTF unespected state"); + break; + } + + return nil; +} + +@end diff --git a/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser_private.h b/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser_private.h new file mode 100644 index 0000000..98abd17 --- /dev/null +++ b/Pods/GRMustache/src/classes/Parsing/GRMustacheExpressionParser_private.h @@ -0,0 +1,44 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheExpression; + +@interface GRMustacheExpressionParser : NSObject + +/** + * Returns an expression from a string. + * + * @param string A string. + * @param empty If there is an error parsing the expression, upon return + * contains YES if the string contains no expression. + * @param error If there is an error parsing the expression, upon return + * contains an NSError object that describes the problem. + * + * @return An expression, or nil if the parsing fails or if the expression is + * empty. + */ +- (GRMustacheExpression *)parseExpression:(NSString *)string empty:(BOOL *)empty error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser.m b/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser.m new file mode 100644 index 0000000..4aa283e --- /dev/null +++ b/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser.m @@ -0,0 +1,528 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheTemplateParser_private.h" +#import "GRMustacheConfiguration_private.h" +#import "GRMustacheToken_private.h" +#import "GRMustacheError.h" + +@interface GRMustacheTemplateParser() + +/** + * The Mustache tag opening delimiter. + */ +@property (nonatomic, copy) NSString *tagStartDelimiter; + +/** + * The Mustache tag opening delimiter. + */ +@property (nonatomic, copy) NSString *tagEndDelimiter; + +// Documented in GRMustacheTemplateParser_private.h +@property (nonatomic, strong) NSMutableSet *pragmas; + +@end + +@implementation GRMustacheTemplateParser +@synthesize delegate=_delegate; +@synthesize tagStartDelimiter=_tagStartDelimiter; +@synthesize tagEndDelimiter=_tagEndDelimiter; +@synthesize pragmas=_pragmas; + +- (instancetype)initWithConfiguration:(GRMustacheConfiguration *)configuration +{ + self = [super init]; + if (self) { + self.tagStartDelimiter = configuration.tagStartDelimiter; + self.tagEndDelimiter = configuration.tagEndDelimiter; + } + return self; +} + +- (void)dealloc +{ + [_tagStartDelimiter release]; + [_tagEndDelimiter release]; + [_pragmas release]; + [super dealloc]; +} + +- (void)parseTemplateString:(NSString *)templateString templateID:(id)templateID +{ + if (templateString == nil) { + if ([_delegate respondsToSelector:@selector(templateParser:didFailWithError:)]) { + [_delegate templateParser:self didFailWithError:[NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeTemplateNotFound + userInfo:[NSDictionary dictionaryWithObject:@"Nil template string can not be parsed." + forKey:NSLocalizedDescriptionKey]]]; + } + return; + } + + // Extract characters + + NSUInteger length = [templateString length]; + const UniChar *characters = CFStringGetCharactersPtr((CFStringRef)templateString); + if (!characters) { + NSMutableData *data = [NSMutableData dataWithLength:length * sizeof(UniChar)]; + [templateString getCharacters:[data mutableBytes] range:(NSRange){ .location = 0, .length = length }]; + characters = [data bytes]; + } + + NSCharacterSet *whitespaceCharacterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + + // state machine internal states + enum { + stateStart, // Something is going to happen. We don't know what yet. Next character will tell. + stateText, // Currently enumerating other characters + stateTag, // Currently enumerating characters of a {{tag}} + stateUnescapedTag, // Currently enumerating characters of a {{{tag}}} + stateSetDelimitersTag, // Currently enumerating characters of a {{=tag=}} + } state = stateStart; + + // Some cached value for "efficient" lookup of {{ and }} + NSString *tagStartDelimiter = self.tagStartDelimiter; + NSString *tagEndDelimiter = self.tagEndDelimiter; + UniChar tagStartDelimiterInitial = [tagStartDelimiter characterAtIndex:0]; + NSUInteger tagStartDelimiterLength = tagStartDelimiter.length; + UniChar tagEndDelimiterInitial = [tagEndDelimiter characterAtIndex:0]; + NSUInteger tagEndDelimiterLength = tagEndDelimiter.length; + + // Some cached value for "efficient" lookup of {{{ and }}} + // + // Mustache spec does not say that what happens to triple mustache tags when + // delimiters are not {{ and }}. It just says to use the & tag prefix: + // {{{ a }}} <=> {{& a }}. + // + // We interpret this as a complete removal of triple mustache tags when + // delimiters are not {{ and }}: unescapedTagStartDelimiterInitial will be 0 + // and we will never enter the stateUnescapedTag state. + BOOL standardDelimiters = [tagStartDelimiter isEqualToString:@"{{"] && [tagEndDelimiter isEqualToString:@"}}"]; + NSString *unescapedTagStartDelimiter = standardDelimiters ? @"{{{" : nil; + NSString *unescapedTagEndDelimiter = standardDelimiters ? @"}}}" : nil; + UniChar unescapedTagStartDelimiterInitial = [unescapedTagStartDelimiter characterAtIndex:0]; + NSUInteger unescapedTagStartDelimiterLength = unescapedTagStartDelimiter.length; + UniChar unescapedTagEndDelimiterInitial = [unescapedTagEndDelimiter characterAtIndex:0]; + NSUInteger unescapedTagEndDelimiterLength = unescapedTagEndDelimiter.length; + + // Some cached value for "efficient" lookup of {{= and =}} + // + // Set delimiters tags {{=<% %>=}} have a dedicated lookup and state, so that + // we support setting to the current delimiters: {{={{ }}=}}. We achieve this + // by exiting the stateSetDelimitersTag state on =}}, not on }}. + NSString *setDelimitersTagStartDelimiter = [NSString stringWithFormat:@"%@=", tagStartDelimiter]; + NSString *setDelimitersTagEndDelimiter = [NSString stringWithFormat:@"=%@", tagEndDelimiter]; + UniChar setDelimitersTagStartDelimiterInitial = [setDelimitersTagStartDelimiter characterAtIndex:0]; + NSUInteger setDelimitersTagStartDelimiterLength = setDelimitersTagStartDelimiter.length; + UniChar setDelimitersTagEndDelimiterInitial = [setDelimitersTagEndDelimiter characterAtIndex:0]; + NSUInteger setDelimitersTagEndDelimiterLength = setDelimitersTagEndDelimiter.length; + + NSUInteger i = 0; // index of current character + NSUInteger start = 0; // index of character at the beginning of the current state + NSUInteger lineNumber = 1; // 1-based index of the current line + NSUInteger tagStartLineNumber = 1; // 1-based index of the beginning of the current tag + for (; i': + type = GRMustacheTokenTypePartial; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength+1, .length = i-(start+tagStartDelimiterLength+1) }; + break; + case '<': + type = GRMustacheTokenTypeInheritablePartial; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength+1, .length = i-(start+tagStartDelimiterLength+1) }; + break; + case '{': + type = GRMustacheTokenTypeUnescapedVariable; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength+1, .length = i-(start+tagStartDelimiterLength+1) }; + break; + case '&': + type = GRMustacheTokenTypeUnescapedVariable; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength+1, .length = i-(start+tagStartDelimiterLength+1) }; + break; + case '%': + type = GRMustacheTokenTypePragma; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength+1, .length = i-(start+tagStartDelimiterLength+1) }; + break; + default: + type = GRMustacheTokenTypeEscapedVariable; + tagInnerRange = (NSRange){ .location = start+tagStartDelimiterLength, .length = i-(start+tagStartDelimiterLength) }; + break; + } + GRMustacheToken *token = [GRMustacheToken tokenWithType:type + templateString:templateString + templateID:templateID + line:tagStartLineNumber + range:(NSRange){ .location = start, .length = (i+tagEndDelimiterLength)-start}]; + token.tagInnerRange = tagInnerRange; + if (![self.delegate templateParser:self shouldContinueAfterParsingToken:token]) return; + + start = i + tagEndDelimiterLength; + state = stateStart; + i += tagEndDelimiterLength - 1; + } + } break; + + case stateUnescapedTag: { + if (c == '\n') + { + ++lineNumber; + } + else if (CHARACTER_STARTS(unescapedTagEndDelimiter)) + { + // Tag + GRMustacheToken *token = [GRMustacheToken tokenWithType:GRMustacheTokenTypeUnescapedVariable + templateString:templateString + templateID:templateID + line:tagStartLineNumber + range:(NSRange){ .location = start, .length = (i+unescapedTagEndDelimiterLength)-start}]; + token.tagInnerRange = (NSRange){ .location = start+unescapedTagStartDelimiterLength, .length = i-(start+unescapedTagStartDelimiterLength) }; + if (![self.delegate templateParser:self shouldContinueAfterParsingToken:token]) return; + + start = i + unescapedTagEndDelimiterLength; + state = stateStart; + i += unescapedTagEndDelimiterLength - 1; + } + } break; + + case stateSetDelimitersTag: { + if (c == '\n') + { + ++lineNumber; + } + else if (CHARACTER_STARTS(setDelimitersTagEndDelimiter)) + { + // Set Delimiters Tag + NSString *innerContent = [templateString substringWithRange:(NSRange){ .location = start+setDelimitersTagStartDelimiterLength, .length = i-(start+setDelimitersTagStartDelimiterLength) }]; + NSArray *newTags = [innerContent componentsSeparatedByCharactersInSet:whitespaceCharacterSet]; + NSMutableArray *nonBlankNewTags = [NSMutableArray array]; + for (NSString *newTag in newTags) { + if (newTag.length > 0) { + [nonBlankNewTags addObject:newTag]; + } + } + if (nonBlankNewTags.count != 2) { + [self failWithParseErrorAtLine:lineNumber description:@"Invalid set delimiters tag" templateID:templateID]; + return; + } + + GRMustacheToken *token = [GRMustacheToken tokenWithType:GRMustacheTokenTypeSetDelimiter + templateString:templateString + templateID:templateID + line:tagStartLineNumber + range:(NSRange){ .location = start, .length = (i+setDelimitersTagEndDelimiterLength)-start}]; + token.tagInnerRange = (NSRange){ .location = start+setDelimitersTagStartDelimiterLength, .length = i-(start+setDelimitersTagStartDelimiterLength) }; + if (![self.delegate templateParser:self shouldContinueAfterParsingToken:token]) return; + + start = i + setDelimitersTagEndDelimiterLength; + state = stateStart; + i += setDelimitersTagEndDelimiterLength - 1; + + // Update tag delimiters, and cached values for "efficient" + // lookup of them (see character loop initialization) + + tagStartDelimiter = [nonBlankNewTags objectAtIndex:0]; + tagEndDelimiter = [nonBlankNewTags objectAtIndex:1]; + tagStartDelimiterInitial = [tagStartDelimiter characterAtIndex:0]; + tagStartDelimiterLength = tagStartDelimiter.length; + tagEndDelimiterInitial = [tagEndDelimiter characterAtIndex:0]; + tagEndDelimiterLength = tagEndDelimiter.length; + + BOOL standardDelimiters = [tagStartDelimiter isEqualToString:@"{{"] && [tagEndDelimiter isEqualToString:@"}}"]; + unescapedTagStartDelimiter = standardDelimiters ? @"{{{" : nil; + unescapedTagEndDelimiter = standardDelimiters ? @"}}}" : nil; + unescapedTagStartDelimiterInitial = [unescapedTagStartDelimiter characterAtIndex:0]; + unescapedTagStartDelimiterLength = unescapedTagStartDelimiter.length; + unescapedTagEndDelimiterInitial = [unescapedTagEndDelimiter characterAtIndex:0]; + unescapedTagEndDelimiterLength = unescapedTagEndDelimiter.length; + + setDelimitersTagStartDelimiter = [NSString stringWithFormat:@"%@=", tagStartDelimiter]; + setDelimitersTagEndDelimiter = [NSString stringWithFormat:@"=%@", tagEndDelimiter]; + setDelimitersTagStartDelimiterInitial = [setDelimitersTagStartDelimiter characterAtIndex:0]; + setDelimitersTagStartDelimiterLength = setDelimitersTagStartDelimiter.length; + setDelimitersTagEndDelimiterInitial = [setDelimitersTagEndDelimiter characterAtIndex:0]; + setDelimitersTagEndDelimiterLength = setDelimitersTagEndDelimiter.length; + } + } break; + } + } + + // EOF + switch (state) { + case stateStart: + break; + + case stateText: { + GRMustacheToken *token = [GRMustacheToken tokenWithType:GRMustacheTokenTypeText + templateString:templateString + templateID:templateID + line:lineNumber + range:(NSRange){ .location = start, .length = i-start}]; + if (![self.delegate templateParser:self shouldContinueAfterParsingToken:token]) return; + } break; + + case stateTag: + case stateUnescapedTag: + case stateSetDelimitersTag: { + [self failWithParseErrorAtLine:tagStartLineNumber description:@"Unclosed Mustache tag" templateID:templateID]; + return; + } break; + } +} + +- (NSString *)parseInheritableSectionName:(NSString *)string empty:(BOOL *)empty error:(NSError **)error +{ + NSCharacterSet *whiteSpace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + NSString *inheritableSectionName = [string stringByTrimmingCharactersInSet:whiteSpace]; + if (inheritableSectionName.length == 0) { + if (empty != NULL) { + *empty = YES; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:@"Missing inheritable section name" + forKey:NSLocalizedDescriptionKey]]; + } + return nil; + } + if ([inheritableSectionName rangeOfCharacterFromSet:whiteSpace].location != NSNotFound) { + if (empty != NULL) { + *empty = NO; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:@"Invalid inheritable section name" + forKey:NSLocalizedDescriptionKey]]; + } + return nil; + } + return inheritableSectionName; +} + +- (NSString *)parseTemplateName:(NSString *)string empty:(BOOL *)empty error:(NSError **)error +{ + NSCharacterSet *whiteSpace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + NSString *templateName = [string stringByTrimmingCharactersInSet:whiteSpace]; + if (templateName.length == 0) { + if (empty != NULL) { + *empty = YES; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:@"Missing template name" + forKey:NSLocalizedDescriptionKey]]; + } + return nil; + } + if ([templateName rangeOfCharacterFromSet:whiteSpace].location != NSNotFound) { + if (empty != NULL) { + *empty = NO; + } + if (error != NULL) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:@"Invalid template name" + forKey:NSLocalizedDescriptionKey]]; + } + return nil; + } + return templateName; +} + +- (NSString *)parsePragma:(NSString *)string +{ + NSString *pragma = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if (pragma.length == 0) { + return nil; + } + return pragma; +} + + +#pragma mark - Private + +/** + * Wrapper around the delegate's `templateParser:shouldContinueAfterParsingToken:` + * method. + */ +- (BOOL)shouldContinueAfterParsingToken:(GRMustacheToken *)token +{ + if ([_delegate respondsToSelector:@selector(templateParser:shouldContinueAfterParsingToken:)]) { + return [_delegate templateParser:self shouldContinueAfterParsingToken:token]; + } + return YES; +} + +/** + * Wrapper around the delegate's `templateParser:didFailWithError:` method. + * + * @param line The line at which the error occurred. + * @param description A human-readable error message + * @param templateID A template ID (see GRMustacheTemplateRepository) + */ +- (void)failWithParseErrorAtLine:(NSInteger)line description:(NSString *)description templateID:(id)templateID +{ + if ([_delegate respondsToSelector:@selector(templateParser:didFailWithError:)]) { + NSString *localizedDescription; + if (templateID) { + localizedDescription = [NSString stringWithFormat:@"Parse error at line %lu of template %@: %@", (unsigned long)line, templateID, description]; + } else { + localizedDescription = [NSString stringWithFormat:@"Parse error at line %lu: %@", (unsigned long)line, description]; + } + [_delegate templateParser:self didFailWithError:[NSError errorWithDomain:GRMustacheErrorDomain + code:GRMustacheErrorCodeParseError + userInfo:[NSDictionary dictionaryWithObject:localizedDescription + forKey:NSLocalizedDescriptionKey]]]; + } +} + +@end diff --git a/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser_private.h b/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser_private.h new file mode 100644 index 0000000..b292e1c --- /dev/null +++ b/Pods/GRMustache/src/classes/Parsing/GRMustacheTemplateParser_private.h @@ -0,0 +1,156 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheToken; +@class GRMustacheTemplateParser; +@class GRMustacheConfiguration; + + +// ============================================================================= +#pragma mark - + +/** + * The protocol for the delegate of a GRMustacheTemplateParser. + * + * The delegate's responsability is to consume tokens and handle parser + * errors. + * + * @see GRMustacheCompiler + */ +@protocol GRMustacheTemplateParserDelegate +@optional + +/** + * Sent after the parser has parsed a token. + * + * @param parser The parser that did find a token. + * @param token The token + * + * @return YES if the parser should continue producing tokens; otherwise, NO. + * + * @see GRMustacheToken + */ +- (BOOL)templateParser:(GRMustacheTemplateParser *)parser shouldContinueAfterParsingToken:(GRMustacheToken *)token GRMUSTACHE_API_INTERNAL; + +/** + * Sent after the token has failed. + * + * @param parser The parser that failed to producing tokens. + * @param error The error that occurred. + */ +- (void)templateParser:(GRMustacheTemplateParser *)parser didFailWithError:(NSError *)error GRMUSTACHE_API_INTERNAL; +@end + + +// ============================================================================= +#pragma mark - GRMustacheTemplateParser + +/** + * The GRMustacheTemplateParser consumes a Mustache template string, and + * produces tokens. + * + * Those tokens are consumed by the parser's delegate. + * + * @see GRMustacheToken + * @see GRMustacheTemplateParserDelegate + */ +@interface GRMustacheTemplateParser : NSObject { +@private + id _delegate; + NSString *_tagStartDelimiter; + NSString *_tagEndDelimiter; + NSMutableSet *_pragmas; +} + +/** + * The parser's delegate. + * + * The delegate is sent messages as the parser interprets a Mustache template + * string. + * + * @see GRMustacheTemplateParserDelegate + */ +@property (nonatomic, assign) id delegate GRMUSTACHE_API_INTERNAL; + +/** + * A set of all pragmas found while parsing. Pragmas are defined via pragma tags + * such as `{{% FILTERS }}`. + */ +@property (nonatomic, strong, readonly) NSMutableSet *pragmas GRMUSTACHE_API_INTERNAL; + +/** + * Returns an initialized parser. + * + * @param configuration The GRMustacheConfiguration that affects the + * parsing phase. + * @return a compiler + */ +- (instancetype)initWithConfiguration:(GRMustacheConfiguration *)configuration GRMUSTACHE_API_INTERNAL; + +/** + * The parser will invoke its delegate as it builds tokens from the template + * string. + * + * @param templateString A Mustache template string + * @param templateID A template ID (see GRMustacheTemplateRepository) + */ +- (void)parseTemplateString:(NSString *)templateString templateID:(id)templateID GRMUSTACHE_API_INTERNAL; + +/** + * Returns a template name from a string. + * + * @param string A string. + * @param empty If there is an error parsing a template name, upon return + * contains YES if the string contains no information. + * @param error If there is an error parsing a template name, upon return + * contains an NSError object that describes the problem. + * + * @return a template name, or nil if the string is not a partial name. + */ +- (NSString *)parseTemplateName:(NSString *)string empty:(BOOL *)empty error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +/** + * Returns an inheritable section name from a string. + * + * @param string A string. + * @param empty If there is an error parsing an identifier, upon return + * contains YES if the string contains no information. + * @param error If there is an error parsing an identifier, upon return + * contains an NSError object that describes the problem. + * + * @return a template name, or nil if the string is not a partial name. + */ +- (NSString *)parseInheritableSectionName:(NSString *)string empty:(BOOL *)empty error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +/** + * Returns a pragma from a string + * + * @param string A string + * + * @return a pragma, or nil if the string is not a pragma. + */ +- (NSString *)parsePragma:(NSString *)string GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Parsing/GRMustacheToken.m b/Pods/GRMustache/src/classes/Parsing/GRMustacheToken.m new file mode 100644 index 0000000..e53f355 --- /dev/null +++ b/Pods/GRMustache/src/classes/Parsing/GRMustacheToken.m @@ -0,0 +1,63 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheToken_private.h" + + +@implementation GRMustacheToken +@synthesize type=_type; +@synthesize templateString=_templateString; +@synthesize templateID=_templateID; +@synthesize line=_line; +@synthesize range=_range; +@synthesize tagInnerRange=_tagInnerRange; + +- (void)dealloc +{ + [_templateString release]; + [_templateID release]; + [super dealloc]; +} + ++ (instancetype)tokenWithType:(GRMustacheTokenType)type templateString:(NSString *)templateString templateID:(id)templateID line:(NSUInteger)line range:(NSRange)range +{ + GRMustacheToken *token = [[[self alloc] init] autorelease]; + token.type = type; + token.templateString = templateString; + token.templateID = templateID; + token.line = line; + token.range = range; + return token; +} + +- (NSString *)templateSubstring +{ + return [_templateString substringWithRange:_range]; +} + +- (NSString *)tagInnerContent +{ + return [_templateString substringWithRange:_tagInnerRange]; +} + +@end + diff --git a/Pods/GRMustache/src/classes/Parsing/GRMustacheToken_private.h b/Pods/GRMustache/src/classes/Parsing/GRMustacheToken_private.h new file mode 100644 index 0000000..26f0852 --- /dev/null +++ b/Pods/GRMustache/src/classes/Parsing/GRMustacheToken_private.h @@ -0,0 +1,183 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +/** + * The kinds of tokens + */ +typedef NS_ENUM(NSInteger, GRMustacheTokenType) { + + /** + * The kind of tokens representing raw template text. + */ + GRMustacheTokenTypeText, + + /** + * The kind of tokens representing escaped variable tags such as `{{name}}`. + */ + GRMustacheTokenTypeEscapedVariable, + + /** + * The kind of tokens representing a comment tag such as `{{! comment }}`. + */ + GRMustacheTokenTypeComment, + + /** + * The kind of tokens representing unescaped variable tag such as + * `{{{name}}}` and `{{&name}}`. + */ + GRMustacheTokenTypeUnescapedVariable, + + /** + * The kind of tokens representing section opening tags such as `{{#name}}`. + */ + GRMustacheTokenTypeSectionOpening, + + /** + * The kind of tokens representing inverted section opening tags such as + * `{{^name}}`. + */ + GRMustacheTokenTypeInvertedSectionOpening, + + /** + * The kind of tokens representing closing tags such as `{{/name}}`. + */ + GRMustacheTokenTypeClosing, + + /** + * The kind of tokens representing partial tags such as `{{>name}}`. + */ + GRMustacheTokenTypePartial, + + /** + * The kind of tokens representing delimiters tags such as `{{=< >=}}`. + */ + GRMustacheTokenTypeSetDelimiter, + + /** + * The kind of tokens representing pragma tags such as `{{%FILTERS}}`. + */ + GRMustacheTokenTypePragma, + + /** + * The kind of tokens representing inheritable partial tags such as + * `{{ +#import "GRMustacheAvailabilityMacros.h" + +@protocol GRMustacheTagDelegate; + +/** + * The GRMustacheContext represents a Mustache rendering context: it internally + * maintains three stacks: + * + * - a *context stack*, that makes it able to provide the current context + * object, and to perform key lookup. + * + * - a *priority context stack*, whose objects define important keys that + * should not be overriden. + * + * - a *tag delegate stack*, so that tag delegates are notified when a Mustache + * tag is rendered. + * + * **Companion guides:** + * + * - https://github.com/groue/GRMustache/blob/master/Guides/view_model.md + * - https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * - https://github.com/groue/GRMustache/blob/master/Guides/rendering_objects.md + * - https://github.com/groue/GRMustache/blob/master/Guides/security.md + * + * @warning GRMustacheContext is not suitable for subclassing. + * + * @see GRMustacheRendering protocol + */ +@interface GRMustacheContext : NSObject { +@private +#define GRMUSTACHE_STACK_TOP_IVAR(stackName) _ ## stackName ## Object +#define GRMUSTACHE_STACK_PARENT_IVAR(stackName) _ ## stackName ## Parent +#define GRMUSTACHE_STACK_DECLARE_IVARS(stackName, type) \ + GRMustacheContext *GRMUSTACHE_STACK_PARENT_IVAR(stackName); \ + type GRMUSTACHE_STACK_TOP_IVAR(stackName) + + GRMUSTACHE_STACK_DECLARE_IVARS(contextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(protectedContextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(hiddenContextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(tagDelegateStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(inheritablePartialNodeStack, id); + + BOOL _unsafeKeyAccess; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Creating Rendering Contexts +//////////////////////////////////////////////////////////////////////////////// + +/** + * Returns an initialized empty rendering context. + * + * Empty contexts do not provide any value for any key. + * + * If you wish to use the services provided by the GRMustache standard library, + * you should create a context with the +[GRMustacheContext contextWithObject:] + * method, like this: + * + * ``` + * [GRMustacheContext contextWithObject:[GRMustache standardLibrary]] + * ``` + * + * @return A rendering context. + * + * @see +[GRMustache standardLibrary] + */ +- (instancetype)init; + +/** + * Returns an empty rendering context. + * + * Empty contexts do not provide any value for any key. + * + * If you wish to use the services provided by the GRMustache standard library, + * you should create a context with the +[GRMustacheContext contextWithObject:] + * method, like this: + * + * ``` + * [GRMustacheContext contextWithObject:[GRMustache standardLibrary]] + * ``` + * + * @return A rendering context. + * + * @see contextWithObject: + * @see +[GRMustache standardLibrary] + * + * @since v6.4 + */ ++ (instancetype)context AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a rendering context containing a single object. + * + * Keys defined by _object_ gets available for template rendering. + * + * ``` + * context = [GRMustacheContext contextWithObject:@{ @"name": @"Arthur" }]; + * [context valueForMustacheKey:@"name"]; // @"Arthur" + * ``` + * + * If _object_ conforms to the GRMustacheTemplateDelegate protocol, it is also + * made the top of the tag delegate stack. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * + * @param object An object + * + * @return A rendering context. + * + * @see contextByAddingObject: + * + * @see GRMustacheTemplateDelegate + * + * @since v6.4 + */ ++ (instancetype)contextWithObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a context containing a single priority object. + * + * Keys defined by _object_ are given priority, which means that they can not be + * overriden by other objects that will eventually enter the context stack. + * + * ``` + * // Create a context with a priority `precious` key + * context = [GRMustacheContext contextWithProtectedObject:@{ @"precious": @"gold" }]; + * + * // Derive a new context by attempting to override the `precious` key: + * context = [context contextByAddingObject:@{ @"precious": @"lead" }]; + * + * // Priority keys can't be overriden + * [context valueForMustacheKey:@"precious"]; // @"gold" + * ``` + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/security.md#priority-keys + * + * @param object An object + * + * @return A rendering context. + * + * @see contextByAddingProtectedObject: + * + * @since v6.4 + */ ++ (instancetype)contextWithProtectedObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a context containing a single tag delegate. + * + * _tagDelegate_ will be notified of the rendering of all tags rendered from the + * receiver or from contexts derived from the receiver. + * + * Unlike contextWithObject: and contextWithProtectedObject:, _tagDelegate_ will + * not provide any key to the templates. It will only be notified of the + * rendering of tags. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * + * @param tagDelegate A tag delegate + * + * @return A rendering context. + * + * @see GRMustacheTagDelegate + * + * @since v6.4 + */ ++ (instancetype)contextWithTagDelegate:(id)tagDelegate AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Deriving New Contexts +//////////////////////////////////////////////////////////////////////////////// + + +/** + * Returns a new rendering context that is the copy of the receiver, and the + * given object added at the top of the context stack. + * + * Keys defined by _object_ gets available for template rendering, and override + * the values defined by objects already contained in the context stack. Keys + * unknown to _object_ will be looked up deeper in the context stack. + * + * ``` + * context = [GRMustacheContext contextWithObject:@{ @"a": @"ignored", @"b": @"foo" }]; + * context = [context contextByAddingObject:@{ @"a": @"bar" }]; + * + * // `a` is overriden + * [context valueForMustacheKey:@"a"]; // @"bar" + * + * // `b` is inherited + * [context valueForMustacheKey:@"b"]; // @"foo" + * ``` + * + * _object_ can not override keys defined by the objects of the priority + * context stack, though. See contextWithProtectedObject: and + * contextByAddingProtectedObject:. + * + * If _object_ conforms to the GRMustacheTemplateDelegate protocol, it is also + * added at the top of the tag delegate stack. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * + * @param object An object + * + * @return A new rendering context. + * + * @see GRMustacheTemplateDelegate + * + * @since v6.0 + */ +- (instancetype)contextByAddingObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a new rendering context that is the copy of the receiver, and the + * given object added at the top of the priority context stack. + * + * Keys defined by _object_ are given priority, which means that they can not be + * overriden by other objects that will eventually enter the context stack. + * + * ``` + * // Derive a context with a priority `precious` key + * context = [context contextByAddingProtectedObject:@{ @"precious": @"gold" }]; + * + * // Derive a new context by attempting to override the `precious` key: + * context = [context contextByAddingObject:@{ @"precious": @"lead" }]; + * + * // Priority keys can't be overriden + * [context valueForMustacheKey:@"precious"]; // @"gold" + * ``` + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/security.md#priority-keys + * + * @param object An object + * + * @return A new rendering context. + * + * @since v6.0 + */ +- (instancetype)contextByAddingProtectedObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a new rendering context that is the copy of the receiver, and the + * given object added at the top of the tag delegate stack. + * + * _tagDelegate_ will be notified of the rendering of all tags rendered from the + * receiver or from contexts derived from the receiver. + * + * Unlike contextByAddingObject: and contextByAddingProtectedObject:, + * _tagDelegate_ will not provide any key to the templates. It will only be + * notified of the rendering of tags. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * + * @param tagDelegate A tag delegate + * + * @return A new rendering context. + * + * @see GRMustacheTagDelegate + * + * @since v6.0 + */ +- (instancetype)contextByAddingTagDelegate:(id)tagDelegate AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Fetching Values from the Context Stack +//////////////////////////////////////////////////////////////////////////////// + +/** + * Returns the object at the top of the receiver's context stack. + * + * The returned object is the same as the one that would be rendered by a + * `{{ . }}` tag. + * + * ``` + * user = ...; + * context = [GRMustacheContext contextWithObject:user]; + * context.topMustacheObject; // user + * ``` + * + * @return The object at the top of the receiver's context stack. + * + * @see contextWithObject: + * @see contextByAddingObject: + * + * @since v6.7 + */ +@property (nonatomic, readonly) id topMustacheObject AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns the value stored in the context stack for the given key. + * + * If you want the value for an full expression such as `user.name` or + * `uppercase(user.name)`, use the hasValue:forMustacheExpression:error: + * method. + * + * ### Search Pattern for valueForMustacheKey + * + * The Mustache value of any object for a given key is defined as: + * + * 1. If the object responds to the `objectForKeyedSubscript:` instance method, + * return the result of this method. + * + * 2. Otherwise, build the list of safe keys: + * a. If the object responds to the `safeMustacheKeys` class method defined + * by the `GRMustacheSafeKeyAccess` protocol, use this method. + * b. Otherwise, use the list of Objective-C properties declared with + * `@property`. + * c. If object is an instance of NSManagedObject, add all the attributes of + * its Core Data entity. + * + * 3. If the key belongs to the list of safe keys, return the result of the + * `valueForKey:` method, unless this method throws NSUndefinedKeyException. + * + * 4. Otherwise, return nil. + * + * Contexts with unsafe key access skip the key validation step. + * + * In this method, the following search pattern is used: + * + * 1. Searches the priority context stack for an object that has a non-nil + * Mustache value for the key. + * + * 2. Otherwise (irrelevant priority context stack), search the context stack + * for an object that has a non-nil Mustache value for the key. + * + * 3. If none of the above situations occurs, returns nil. + * + * **Companion guides:** https://github.com/groue/GRMustache/blob/master/Guides/runtime.md, + * https://github.com/groue/GRMustache/blob/master/Guides/view_model.md + * + * @param key a key such as @"name" + * + * @return The value found in the context stack for the given key. + * + * @see contextWithUnsafeKeyAccess + * @see hasValue:forMustacheExpression:error: + * + * @since v6.6 + */ +- (id)valueForMustacheKey:(NSString *)key AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Evaluates an expression such as `name`, or `uppercase(user.name)`. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/view_model.md + * + * @param value Upon return contains the value of the expression. + * @param expression An expression. + * @param error If there is an error computing the value, upon return + * contains an NSError object that describes the problem. + * + * @return YES if the value could be computed. + * + * @see valueForMustacheKey: + * + * @since v6.8 + */ +- (BOOL)hasValue:(id *)value forMustacheExpression:(NSString *)expression error:(NSError **)error AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + + +//////////////////////////////////////////////////////////////////////////////// +/// @name Unsafe Key Access +//////////////////////////////////////////////////////////////////////////////// + +/** + * Returns whether this context allows unsafe key access or not. + * + * @since v7.0 + */ +@property (nonatomic, readonly) BOOL unsafeKeyAccess AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a new context with unsafe key access. + * + * Unsafe key access allows this context, and all contexts derived from it, to + * access keys that are normally forbidden: keys that are not declared as + * Objective-C properties, or keys that do not belong to the result of the + * `safeMustacheKeys` method. + * + * Compare: + * + * ``` + * @interface DBRecord : NSObject + * - (void)deleteRecord; + * @end + * + * @implementation DBRecord + * - (void)deleteRecord + * { + *     NSLog(@"Oooops, your record was just deleted!"); + * } + * @end + * + * DBRecord *record = ...; + * NSString *templateString = @"{{ deleteRecord }}"; + * GRMustacheTemplate * template = [GRMustacheTemplate templateWithString:templateString error:NULL]; + * + * // Safe rendering of the dangerous template: record is not deleted. + * [template renderObject:record error:NULL]; + * + * // Unsafe rendering of the dangerous template: record is deleted. + * template.baseContext = [GRMustacheContext contextWithUnsafeKeyAccess]; + * [template renderObject:record error:NULL]; + * ``` + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/security.md + * + * @see GRMustacheSafeKeyAccess + * + * @since v7.0 + */ ++ (instancetype)contextWithUnsafeKeyAccess AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a new rendering context that is the copy of the receiver, with unsafe + * key access. + * + * Unsafe key access allows this context, and all contexts derived from it, to + * access keys that are normally forbidden: keys that are not declared as + * Objective-C properties, or keys that do not belong to the result of the + * `safeMustacheKeys` method. + * + * Compare: + * + * ``` + * @interface DBRecord : NSObject + * - (void)deleteRecord; + * @end + * + * @implementation DBRecord + * - (void)deleteRecord + * { + *     NSLog(@"Oooops, your record was just deleted!"); + * } + * @end + * + * DBRecord *record = ...; + * NSString *templateString = @"{{ deleteRecord }}"; + * GRMustacheTemplate * template = [GRMustacheTemplate templateWithString:templateString error:NULL]; + * + * // Safe rendering of the dangerous template: record is not deleted. + * [template renderObject:record error:NULL]; + * + * // Unsafe rendering of the dangerous template: record is deleted. + * template.baseContext = [template.baseContext contextWithUnsafeKeyAccess]; + * [template renderObject:record error:NULL]; + * ``` + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/security.md + * + * @see GRMustacheSafeKeyAccess + * + * @since v7.0 + */ +- (instancetype)contextWithUnsafeKeyAccess AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheContext.m b/Pods/GRMustache/src/classes/Rendering/GRMustacheContext.m new file mode 100644 index 0000000..5eecc66 --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheContext.m @@ -0,0 +1,458 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import +#import "GRMustacheContext_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheExpression_private.h" +#import "GRMustacheExpressionParser_private.h" +#import "GRMustacheKeyAccess_private.h" +#import "GRMustachePartialNode_private.h" +#import "GRMustacheInheritablePartialNode_private.h" +#import "GRMustacheTagDelegate.h" +#import "GRMustacheExpressionInvocation_private.h" + +#define GRMUSTACHE_STACK_RELEASE(stackName) \ + [GRMUSTACHE_STACK_TOP_IVAR(stackName) release]; \ + [GRMUSTACHE_STACK_PARENT_IVAR(stackName) release] + +#define GRMUSTACHE_STACK_INIT(stackName, context, object) \ + GRMUSTACHE_STACK_TOP(stackName, context) = [object retain] + +#define GRMUSTACHE_STACK_COPY(stackName, sourceContext, targetContext) \ + GRMUSTACHE_STACK_TOP(stackName, targetContext) = [GRMUSTACHE_STACK_TOP(stackName, sourceContext) retain]; \ + GRMUSTACHE_STACK_PARENT(stackName, targetContext) = [GRMUSTACHE_STACK_PARENT(stackName, sourceContext) retain] + +#define GRMUSTACHE_STACK_PUSH(stackName, sourceContext, targetContext, object) \ + NSAssert(object, @"WTF"); \ + if (GRMUSTACHE_STACK_TOP(stackName, sourceContext)) { \ + GRMUSTACHE_STACK_PARENT(stackName, targetContext) = [sourceContext retain]; \ + } \ + GRMUSTACHE_STACK_TOP(stackName, targetContext) = [object retain]; + +#define GRMUSTACHE_STACK_TOP(stackName, context) context->GRMUSTACHE_STACK_TOP_IVAR(stackName) + +#define GRMUSTACHE_STACK_PARENT(stackName, context) context->GRMUSTACHE_STACK_PARENT_IVAR(stackName) + +#define GRMUSTACHE_STACK_ENUMERATE(stackName, sourceContext, context) \ + if (GRMUSTACHE_STACK_TOP(stackName, sourceContext)) \ + for (GRMustacheContext *context = sourceContext; context; context = GRMUSTACHE_STACK_PARENT(stackName, context)) + +// ============================================================================= +#pragma mark - GRMustacheTagDelegate conformance + +static pthread_key_t GRTagDelegateClassesKey; +void freeTagDelegateClasses(void *objects) { + CFRelease((CFMutableDictionaryRef)objects); +} +#define setupTagDelegateClasses() pthread_key_create(&GRTagDelegateClassesKey, freeTagDelegateClasses) +#define getCurrentThreadTagDelegateClasses() (CFMutableDictionaryRef)pthread_getspecific(GRTagDelegateClassesKey) +#define setCurrentThreadTagDelegateClasses(classes) pthread_setspecific(GRTagDelegateClassesKey, classes) + +static BOOL objectConformsToTagDelegateProtocol(id object) +{ + if (object == nil) { + return NO; + } + + CFMutableDictionaryRef classes = getCurrentThreadTagDelegateClasses(); + if (!classes) { + classes = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + setCurrentThreadTagDelegateClasses(classes); + } + + Class klass = [object class]; + intptr_t conform = (intptr_t)CFDictionaryGetValue(classes, klass); + if (conform == 0) { + conform = [klass conformsToProtocol:@protocol(GRMustacheTagDelegate)] ? 1 : 2; + CFDictionarySetValue(classes, klass, (void *)conform); + } + return (conform == 1); +} + + +// ============================================================================= +#pragma mark - GRMustacheContext + +@implementation GRMustacheContext + ++ (void)initialize +{ + setupTagDelegateClasses(); +} + +- (id)resolveTemplateASTNode:(id)templateASTNode +{ + if (!GRMUSTACHE_STACK_TOP(inheritablePartialNodeStack, self)) { + return templateASTNode; + } + + NSMutableSet *usedTemplateASTs = [[NSMutableSet alloc] init]; + GRMUSTACHE_STACK_ENUMERATE(inheritablePartialNodeStack, self, context) { + GRMustacheInheritablePartialNode *inheritablePartialNode = GRMUSTACHE_STACK_TOP(inheritablePartialNodeStack, context); + GRMustacheTemplateAST *templateAST = inheritablePartialNode.partialNode.templateAST; + if ([usedTemplateASTs containsObject:templateAST]) { + continue; + } + id resolvedASTNode = [inheritablePartialNode resolveTemplateASTNode:templateASTNode]; + if (resolvedASTNode != templateASTNode) { + [usedTemplateASTs addObject:templateAST]; + } + templateASTNode = resolvedASTNode; + } + [usedTemplateASTs release]; + + return templateASTNode; +} + +- (BOOL)unsafeKeyAccess +{ + return _unsafeKeyAccess; +} + + +// ============================================================================= +#pragma mark - Creating Contexts + ++ (instancetype)context +{ + return [[[self alloc] init] autorelease]; +} + ++ (instancetype)contextWithUnsafeKeyAccess +{ + GRMustacheContext *context = [[[self alloc] init] autorelease]; + context->_unsafeKeyAccess = YES; + return context; +} + ++ (instancetype)contextWithObject:(id)object +{ + GRMustacheContext *context = [[[self alloc] init] autorelease]; + GRMUSTACHE_STACK_INIT(contextStack, context, object); + if (objectConformsToTagDelegateProtocol(object)) { + GRMUSTACHE_STACK_INIT(tagDelegateStack, context, object); + } + return context; +} + ++ (instancetype)contextWithProtectedObject:(id)object +{ + GRMustacheContext *context = [[[self alloc] init] autorelease]; + GRMUSTACHE_STACK_INIT(protectedContextStack, context, object); + return context; +} + ++ (instancetype)contextWithTagDelegate:(id)tagDelegate +{ + GRMustacheContext *context = [[[self alloc] init] autorelease]; + GRMUSTACHE_STACK_INIT(tagDelegateStack, context, tagDelegate); + return context; +} + +- (void)dealloc +{ + GRMUSTACHE_STACK_RELEASE(contextStack); + GRMUSTACHE_STACK_RELEASE(protectedContextStack); + GRMUSTACHE_STACK_RELEASE(hiddenContextStack); + GRMUSTACHE_STACK_RELEASE(tagDelegateStack); + GRMUSTACHE_STACK_RELEASE(inheritablePartialNodeStack); + [super dealloc]; +} + + +// ============================================================================= +#pragma mark - Deriving Contexts + +- (instancetype)contextByAddingTagDelegate:(id)tagDelegate +{ + if (tagDelegate == nil) { + return self; + } + + GRMustacheContext *context = [GRMustacheContext context]; + context->_unsafeKeyAccess = _unsafeKeyAccess; + + GRMUSTACHE_STACK_COPY(contextStack, self, context); + GRMUSTACHE_STACK_COPY(protectedContextStack, self, context); + GRMUSTACHE_STACK_COPY(hiddenContextStack, self, context); + GRMUSTACHE_STACK_COPY(inheritablePartialNodeStack, self, context); + + GRMUSTACHE_STACK_PUSH(tagDelegateStack, self, context, tagDelegate); + + return context; +} + +- (instancetype)newContextByAddingObject:(id)object +{ + if (object == nil) { + return [self retain]; + } + + GRMustacheContext *context = [[GRMustacheContext alloc] init]; + context->_unsafeKeyAccess = _unsafeKeyAccess; + + GRMUSTACHE_STACK_COPY(protectedContextStack, self, context); + GRMUSTACHE_STACK_COPY(hiddenContextStack, self, context); + GRMUSTACHE_STACK_COPY(inheritablePartialNodeStack, self, context); + GRMUSTACHE_STACK_COPY(tagDelegateStack, self, context); + + GRMUSTACHE_STACK_PUSH(contextStack, self, context, object); + + if (objectConformsToTagDelegateProtocol(object)) { + GRMUSTACHE_STACK_PUSH(tagDelegateStack, self, context, object); + } else { + GRMUSTACHE_STACK_COPY(tagDelegateStack, self, context); + } + + return context; +} + +- (instancetype)contextByAddingObject:(id)object +{ + return [[self newContextByAddingObject:object] autorelease]; +} + +- (instancetype)contextByAddingProtectedObject:(id)object +{ + if (object == nil) { + return self; + } + + GRMustacheContext *context = [GRMustacheContext context]; + context->_unsafeKeyAccess = _unsafeKeyAccess; + + GRMUSTACHE_STACK_COPY(contextStack, self, context); + GRMUSTACHE_STACK_COPY(hiddenContextStack, self, context); + GRMUSTACHE_STACK_COPY(inheritablePartialNodeStack, self, context); + GRMUSTACHE_STACK_COPY(tagDelegateStack, self, context); + + GRMUSTACHE_STACK_PUSH(protectedContextStack, self, context, object); + + return context; +} + +- (instancetype)contextByAddingHiddenObject:(id)object +{ + if (object == nil) { + return self; + } + + GRMustacheContext *context = [GRMustacheContext context]; + context->_unsafeKeyAccess = _unsafeKeyAccess; + + GRMUSTACHE_STACK_COPY(contextStack, self, context); + GRMUSTACHE_STACK_COPY(protectedContextStack, self, context); + GRMUSTACHE_STACK_COPY(inheritablePartialNodeStack, self, context); + GRMUSTACHE_STACK_COPY(tagDelegateStack, self, context); + + GRMUSTACHE_STACK_PUSH(hiddenContextStack, self, context, object); + + return context; +} + +- (instancetype)contextByAddingInheritablePartialNode:(GRMustacheInheritablePartialNode *)inheritablePartialNode +{ + if (inheritablePartialNode == nil) { + return self; + } + + GRMustacheContext *context = [GRMustacheContext context]; + context->_unsafeKeyAccess = _unsafeKeyAccess; + + GRMUSTACHE_STACK_COPY(contextStack, self, context); + GRMUSTACHE_STACK_COPY(protectedContextStack, self, context); + GRMUSTACHE_STACK_COPY(hiddenContextStack, self, context); + GRMUSTACHE_STACK_COPY(tagDelegateStack, self, context); + + GRMUSTACHE_STACK_PUSH(inheritablePartialNodeStack, self, context, inheritablePartialNode); + + return context; +} + +- (instancetype)contextWithUnsafeKeyAccess +{ +#define GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(stackName) \ + GRMUSTACHE_STACK_ENUMERATE(stackName, self, __context) { \ + GRMustacheContext *__unsafeContext = CFDictionaryGetValue(unsafeContextForContext, __context); \ + if (!__unsafeContext) { \ + __unsafeContext = [GRMustacheContext contextWithUnsafeKeyAccess]; \ + GRMUSTACHE_STACK_COPY(contextStack, __context, __unsafeContext); \ + GRMUSTACHE_STACK_COPY(protectedContextStack, __context, __unsafeContext); \ + GRMUSTACHE_STACK_COPY(hiddenContextStack, __context, __unsafeContext); \ + GRMUSTACHE_STACK_COPY(tagDelegateStack, __context, __unsafeContext); \ + GRMUSTACHE_STACK_COPY(inheritablePartialNodeStack, __context, __unsafeContext); \ + CFDictionarySetValue(unsafeContextForContext, __context, __unsafeContext); \ + } \ + } + +#define GRMUSTACHE_UPDATE_UNSAFE_PARENT(stackName, context) { \ + GRMustacheContext *__safeParent = GRMUSTACHE_STACK_PARENT(stackName, context); \ + if (__safeParent) { \ + GRMustacheContext *__unsafeParent = CFDictionaryGetValue(unsafeContextForContext, __safeParent); \ + [__safeParent release]; \ + GRMUSTACHE_STACK_PARENT(stackName, context) = [__unsafeParent retain]; \ + } \ +} + + // Duplicate contexts of all stacks into unsafe contexts. + // The parents of unsafe contexts are still the safe ones, that we'll update later. + + CFMutableDictionaryRef unsafeContextForContext = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + + GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(contextStack); + GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(protectedContextStack); + GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(hiddenContextStack); + GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(tagDelegateStack); + GRMUSTACHE_CREATE_DEEP_UNSAFE_CONTEXTS(inheritablePartialNodeStack); + + + // Update safe parents of unsafe contexts with unsafe ones + + CFIndex count = CFDictionaryGetCount(unsafeContextForContext); + GRMustacheContext **unsafeContexts = malloc(count * sizeof(GRMustacheContext *)); + if (unsafeContexts == NULL) { + // Allocation failed. + // + // This method is supposed to return a newly created object, so we can + // behave like failing allocating methods and return nil. + // + // And make sure we cleanup allocated memory before. + CFRelease(unsafeContextForContext); + return nil; + } + CFDictionaryGetKeysAndValues(unsafeContextForContext, NULL, (const void **)unsafeContexts); + for (CFIndex i = 0; i < count; ++i) { + GRMustacheContext *unsafeContext = unsafeContexts[i]; + GRMUSTACHE_UPDATE_UNSAFE_PARENT(contextStack, unsafeContext); + GRMUSTACHE_UPDATE_UNSAFE_PARENT(protectedContextStack, unsafeContext); + GRMUSTACHE_UPDATE_UNSAFE_PARENT(hiddenContextStack, unsafeContext); + GRMUSTACHE_UPDATE_UNSAFE_PARENT(tagDelegateStack, unsafeContext); + GRMUSTACHE_UPDATE_UNSAFE_PARENT(inheritablePartialNodeStack, unsafeContext); + } + free(unsafeContexts); + + + // Done + + GRMustacheContext *unsafeContext = CFDictionaryGetValue(unsafeContextForContext, self); + CFRelease(unsafeContextForContext); + return unsafeContext; +} + +// ============================================================================= +#pragma mark - Context Stack + +- (id)topMustacheObject +{ + return [[GRMUSTACHE_STACK_TOP(contextStack, self) retain] autorelease]; +} + +- (id)valueForMustacheKey:(NSString *)key +{ + return [self valueForMustacheKey:key protected:NULL]; +} + +- (id)valueForMustacheKey:(NSString *)key protected:(BOOL *)protected +{ + // First look for in the protected context stack + + GRMUSTACHE_STACK_ENUMERATE(protectedContextStack, self, context) { + id value = [GRMustacheKeyAccess valueForMustacheKey:key inObject:GRMUSTACHE_STACK_TOP(protectedContextStack, context) unsafeKeyAccess:context->_unsafeKeyAccess]; + if (value != nil) { + if (protected != NULL) { + *protected = YES; + } + return value; + } + } + + + // Then look for in the regular context stack + + GRMUSTACHE_STACK_ENUMERATE(contextStack, self, context) { + // First check for contextObject: + // + // context = [GRMustacheContext contextWithObject:@{key:value}]; + // assert([context valueForKey:key] == value); + id contextObject = GRMUSTACHE_STACK_TOP(contextStack, context); + BOOL hidden = NO; + GRMUSTACHE_STACK_ENUMERATE(hiddenContextStack, self, hiddenContext) { + if (contextObject == GRMUSTACHE_STACK_TOP(hiddenContextStack, hiddenContext)) { + hidden = YES; + break; + } + } + if (hidden) { continue; } + id value = [GRMustacheKeyAccess valueForMustacheKey:key inObject:contextObject unsafeKeyAccess:context->_unsafeKeyAccess]; + if (value != nil) { + if (protected != NULL) { + *protected = NO; + } + return value; + } + } + + + // OK give up now + + return nil; +} + +- (BOOL)hasValue:(id *)value forMustacheExpression:(NSString *)string error:(NSError **)error +{ + GRMustacheExpressionParser *parser = [[[GRMustacheExpressionParser alloc] init] autorelease]; + GRMustacheExpression *expression = [parser parseExpression:string empty:NULL error:error]; + + GRMustacheExpressionInvocation *invocation = [[[GRMustacheExpressionInvocation alloc] init] autorelease]; + invocation.context = self; + invocation.expression = expression; + if (![invocation invokeReturningError:error]) { + return NO; + } + + if (value) { + *value = invocation.value; + } + return YES; +} + + +// ============================================================================= +#pragma mark - Tag Delegates Stack + +- (NSArray *)tagDelegateStack +{ + NSMutableArray *tagDelegateStack = nil; + + GRMUSTACHE_STACK_ENUMERATE(tagDelegateStack, self, context) { + if (!tagDelegateStack) { + tagDelegateStack = [NSMutableArray array]; + } + [tagDelegateStack insertObject:GRMUSTACHE_STACK_TOP(tagDelegateStack, context) atIndex:0]; + } + + return tagDelegateStack; +} + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheContext_private.h b/Pods/GRMustache/src/classes/Rendering/GRMustacheContext_private.h new file mode 100644 index 0000000..f1836ea --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheContext_private.h @@ -0,0 +1,183 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@protocol GRMustacheTagDelegate; +@protocol GRMustacheTemplateASTNode; +@class GRMustacheInheritablePartialNode; + +/** + * The GRMustacheContext maintains the following stacks: + * + * - a context stack, + * - a protected context stack, + * - a hidden context stack, + * - a tag delegate stack, + * - an inheritable partial stack. + * + * As such, it is able to: + * + * - Provide the current context object (the top of the context stack). + * + * - Perform a key lookup, starting with the protected context stack, then + * looking in the context stack, avoiding objects in the hidden context stack. + * + * For a full discussion of the interaction between the protected and the + * hidden stacks, see the implementation of + * [GRMustacheTag renderContentType:inBuffer:withContext:error:]. + * + * - Let tag delegates interpret rendered values. + * + * - Let inheritable partial templates override AST nodes. + */ +@interface GRMustacheContext : NSObject { +@private + +#define GRMUSTACHE_STACK_TOP_IVAR(stackName) _ ## stackName ## Object +#define GRMUSTACHE_STACK_PARENT_IVAR(stackName) _ ## stackName ## Parent +#define GRMUSTACHE_STACK_DECLARE_IVARS(stackName, type) \ + GRMustacheContext *GRMUSTACHE_STACK_PARENT_IVAR(stackName); \ + type GRMUSTACHE_STACK_TOP_IVAR(stackName) + + GRMUSTACHE_STACK_DECLARE_IVARS(contextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(protectedContextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(hiddenContextStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(tagDelegateStack, id); + GRMUSTACHE_STACK_DECLARE_IVARS(inheritablePartialNodeStack, GRMustacheInheritablePartialNode *); + + BOOL _unsafeKeyAccess; +} + +// Documented in GRMustacheContext.h ++ (instancetype)context GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h ++ (instancetype)contextWithUnsafeKeyAccess GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h ++ (instancetype)contextWithObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h ++ (instancetype)contextWithProtectedObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h ++ (instancetype)contextWithTagDelegate:(id)tagDelegate GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (instancetype)contextByAddingObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (instancetype)contextByAddingProtectedObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (instancetype)contextByAddingTagDelegate:(id)tagDelegate GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (instancetype)contextWithUnsafeKeyAccess GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (BOOL)hasValue:(id *)value forMustacheExpression:(NSString *)expression error:(NSError **)error GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +- (id)valueForMustacheKey:(NSString *)key GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +// @see -[GRMustacheImplicitIteratorExpression hasValue:withContext:protected:error:] +@property (nonatomic, readonly) id topMustacheObject GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheContext.h +@property (nonatomic, readonly) BOOL unsafeKeyAccess GRMUSTACHE_API_PUBLIC; + +/** + * Same as [contextByAddingObject:object], but returns a retained object. + * This method helps efficiently managing memory, and targeting slow methods. + */ +- (instancetype)newContextByAddingObject:(id)object GRMUSTACHE_API_INTERNAL; + +/** + * Returns a GRMustacheContext object identical to the receiver, but for the + * hidden object stack that is extended with _object_. + * + * Hidden objects can not be queried by the valueForMustacheKey:protected: + * method. + * + * For a full discussion of the interaction between the protected and the hidden + * stacks, see the implementation of + * [GRMustacheTag renderContentType:inBuffer:withContext:error:]. + * + * @param object An object that should be hidden. + * + * @return A GRMustacheContext object. + * + * @see [GRMustacheContext valueForMustacheKey:protected:] + */ +- (instancetype)contextByAddingHiddenObject:(id)object GRMUSTACHE_API_INTERNAL; + +/** + * Returns a GRMustacheContext object identical to the receiver, but for the + * inheritable partial stack that is extended with _inheritablePartial_. + * + * @param inheritablePartialNode An inheritable partial + * + * @return A GRMustacheContext object. + * + * @see GRMustacheInheritablePartialNode + * @see [GRMustacheInheritablePartialNode renderWithContext:inBuffer:error:] + */ +- (instancetype)contextByAddingInheritablePartialNode:(GRMustacheInheritablePartialNode *)inheritablePartialNode GRMUSTACHE_API_INTERNAL; + +/** + * Performs a key lookup in the receiver's context stack, and returns the found + * value. + * + * @param key The searched key. + * @param protected Upon return, is YES if the value comes from the protected + * context stack. + * + * @return The value found in the context stack. + * + * @see -[GRMustacheIdentifierExpression hasValue:withContext:protected:error:] + */ +- (id)valueForMustacheKey:(NSString *)key protected:(BOOL *)protected GRMUSTACHE_API_INTERNAL; + +/** + * In the context of template inheritance, return the node that should be + * rendered in lieu of the node argument. + * + * @param ASTNode A node + * + * @return The resolution of the node in the context of Mustache template + * inheritance. + */ +- (id)resolveTemplateASTNode:(id)templateASTNode GRMUSTACHE_API_INTERNAL; + +/** + * Returns an array containing all tag delegates in the delegate stack. + * Array may be null (meaning there is no tag delegate in the stack). + * + * Last object is the top object in the delegate stack. + */ +- (NSArray *)tagDelegateStack GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation.m b/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation.m new file mode 100644 index 0000000..435242e --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation.m @@ -0,0 +1,135 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpressionInvocation_private.h" +#import "GRMustacheExpressionVisitor_private.h" +#import "GRMustacheFilter_private.h" +#import "GRMustacheScopedExpression_private.h" +#import "GRMustacheIdentifierExpression_private.h" +#import "GRMustacheFilteredExpression_private.h" +#import "GRMustacheContext_private.h" +#import "GRMustacheToken_private.h" +#import "GRMustacheKeyAccess_private.h" +#import "GRMustacheError.h" + +@interface GRMustacheExpressionInvocation() +@end + +@implementation GRMustacheExpressionInvocation +@synthesize context=_context; +@synthesize expression=_expression; +@synthesize value=_value; +@synthesize valueIsProtected=_valueIsProtected; + +- (BOOL)invokeReturningError:(NSError **)error +{ + return [_expression acceptVisitor:self error:error]; +} + + +#pragma mark - + +- (BOOL)visitFilteredExpression:(GRMustacheFilteredExpression *)expression error:(NSError **)error +{ + if (![expression.filterExpression acceptVisitor:self error:error]) { + return NO; + } + id filter = _value; + + if (![expression.argumentExpression acceptVisitor:self error:error]) { + return NO; + } + id argument = _value; + + if (filter == nil) { + GRMustacheToken *token = expression.token; + NSString *renderingErrorDescription = nil; + if (token) { + if (token.templateID) { + renderingErrorDescription = [NSString stringWithFormat:@"Missing filter in tag `%@` at line %lu of template %@", token.templateSubstring, (unsigned long)token.line, token.templateID]; + } else { + renderingErrorDescription = [NSString stringWithFormat:@"Missing filter in tag `%@` at line %lu", token.templateSubstring, (unsigned long)token.line]; + } + } else { + renderingErrorDescription = [NSString stringWithFormat:@"Missing filter"]; + } + NSError *renderingError = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeRenderingError userInfo:[NSDictionary dictionaryWithObject:renderingErrorDescription forKey:NSLocalizedDescriptionKey]]; + if (error != NULL) { + *error = renderingError; + } + return NO; + } + + if (![filter respondsToSelector:@selector(transformedValue:)]) { + GRMustacheToken *token = expression.token; + NSString *renderingErrorDescription = nil; + if (token) { + if (token.templateID) { + renderingErrorDescription = [NSString stringWithFormat:@"Object does not conform to GRMustacheFilter protocol in tag `%@` at line %lu of template %@: %@", token.templateSubstring, (unsigned long)token.line, token.templateID, filter]; + } else { + renderingErrorDescription = [NSString stringWithFormat:@"Object does not conform to GRMustacheFilter protocol in tag `%@` at line %lu: %@", token.templateSubstring, (unsigned long)token.line, filter]; + } + } else { + renderingErrorDescription = [NSString stringWithFormat:@"Object does not conform to GRMustacheFilter protocol: %@", filter]; + } + NSError *renderingError = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeRenderingError userInfo:[NSDictionary dictionaryWithObject:renderingErrorDescription forKey:NSLocalizedDescriptionKey]]; + if (error != NULL) { + *error = renderingError; + } + return NO; + } + + if (expression.isCurried && [filter respondsToSelector:@selector(filterByCurryingArgument:)]) { + _value = [(id)filter filterByCurryingArgument:argument]; + } else { + _value = [(id)filter transformedValue:argument]; + } + + _valueIsProtected = NO; + return YES; +} + +- (BOOL)visitIdentifierExpression:(GRMustacheIdentifierExpression *)expression error:(NSError **)error +{ + _value = [_context valueForMustacheKey:expression.identifier protected:&_valueIsProtected]; + return YES; +} + +- (BOOL)visitScopedExpression:(GRMustacheScopedExpression *)expression error:(NSError **)error +{ + if (![expression.baseExpression acceptVisitor:self error:error]) { + return NO; + } + + _value = [GRMustacheKeyAccess valueForMustacheKey:expression.identifier inObject:_value unsafeKeyAccess:_context.unsafeKeyAccess]; + _valueIsProtected = NO; + return YES; +} + +- (BOOL)visitImplicitIteratorExpression:(GRMustacheImplicitIteratorExpression *)expression error:(NSError **)error +{ + _value = [_context topMustacheObject]; + _valueIsProtected = NO; + return YES; +} + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation_private.h b/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation_private.h new file mode 100644 index 0000000..316fd53 --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheExpressionInvocation_private.h @@ -0,0 +1,65 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheContext; +@class GRMustacheExpression; + +/** + * TODO + */ +@interface GRMustacheExpressionInvocation : NSObject { +@private + GRMustacheContext *_context; + GRMustacheExpression *_expression; + id _value; + BOOL _valueIsProtected; +} + +/** + * TODO + */ +@property (nonatomic, assign) GRMustacheContext *context GRMUSTACHE_API_INTERNAL; + +/** + * TODO + */ +@property (nonatomic, assign) GRMustacheExpression *expression GRMUSTACHE_API_INTERNAL; + +/** + * TODO + */ +@property (nonatomic, assign, readonly) id value GRMUSTACHE_API_INTERNAL; + +/** + * TODO + */ +@property (nonatomic, readonly) BOOL valueIsProtected GRMUSTACHE_API_INTERNAL; + +/** + * TODO + */ +- (BOOL)invokeReturningError:(NSError **)error GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.h b/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.h new file mode 100644 index 0000000..b89e2ec --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.h @@ -0,0 +1,125 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef GRMUSTACHE_FILTER +#define GRMUSTACHE_FILTER + +#import +#import "GRMustacheAvailabilityMacros.h" + + +// ============================================================================= +#pragma mark - + + +/** + * The protocol for implementing GRMustache filters. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/filters.md + * + * The responsability of a GRMustacheFilter is to transform a value into + * another. + * + * For example, the tag `{{ uppercase(name) }}` uses a filter object that + * returns the uppercase version of its input. + * + * @since v4.3 + */ +@protocol GRMustacheFilter +@required + +//////////////////////////////////////////////////////////////////////////////// +/// @name Transforming Values +//////////////////////////////////////////////////////////////////////////////// + +/** + * Applies some transformation to its input, and returns the transformed value. + * + * @param object An object to be processed by the filter. + * + * @return A transformed value. + * + * @since v4.3 + */ +- (id)transformedValue:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end + + + +// ============================================================================= +#pragma mark - GRMustacheFilter + +/** + * The GRMustacheFilter class helps building mustache filters without writing a + * custom class that conforms to the GRMustacheFilter protocol. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/filters.md + * + * @see GRMustacheFilter protocol + * + * @since v4.3 + */ +@interface GRMustacheFilter : NSObject + +//////////////////////////////////////////////////////////////////////////////// +/// @name Creating Filters +//////////////////////////////////////////////////////////////////////////////// + +/** + * Returns a GRMustacheFilter object that executes the provided block when + * tranforming a value. + * + * @param block The block that transforms its input. + * + * @return a GRMustacheFilter object. + * + * @since v4.3 + * + * @see variadicFilterWithBlock: + */ ++ (id)filterWithBlock:(id(^)(id value))block AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a GRMustacheFilter object that executes the provided block, given an + * array of arguments. + * + * Those filters can evaluate expressions like `{{ f(a,b) }}`. + * + * GRMustache will invoke the filter regardless of the number of arguments in + * the template: `{{ f(a) }}`, `{{ f(a,b) }}` and `{{ f(a,b,c) }}` will provide + * arrays of 1, 2, and 3 arguments respectively. It is your responsability to + * check that you are provided with as many arguments as you expect. + * + * @param block The block that transforms its input. + * + * @return a GRMustacheFilter object. + * + * @since v5.5 + * + * @see filterWithBlock: + */ ++ (id)variadicFilterWithBlock:(id(^)(NSArray *arguments))block AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end + +#endif diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.m b/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.m new file mode 100644 index 0000000..bbbc549 --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter.m @@ -0,0 +1,155 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheFilter_private.h" + +// ============================================================================= +#pragma mark - Private concrete class GRMustacheBlockFilter + +/** + * Private subclass of GRMustacheFilter that filters a single argument by + * calling a block. + */ +@interface GRMustacheBlockFilter: GRMustacheFilter { +@private + id(^_block)(id value); +} +- (instancetype)initWithBlock:(id(^)(id value))block; +@end + + +// ============================================================================= +#pragma mark - Private concrete class GRMustacheBlockVariadicFilter + +/** + * Private subclass of GRMustacheFilter that filters an array of arguments by + * calling a block. + */ +@interface GRMustacheBlockVariadicFilter: GRMustacheFilter { +@private + NSArray *_arguments; + id(^_block)(NSArray *arguments); +} +- (instancetype)initWithBlock:(id(^)(NSArray *arguments))block arguments:(NSArray *)arguments; +@end + + +// ============================================================================= +#pragma mark - GRMustacheFilter + +@implementation GRMustacheFilter + ++ (id)filterWithBlock:(id(^)(id value))block +{ + return [[[GRMustacheBlockFilter alloc] initWithBlock:block] autorelease]; +} + ++ (id)variadicFilterWithBlock:(id(^)(NSArray *arguments))block +{ + return [[[GRMustacheBlockVariadicFilter alloc] initWithBlock:block arguments:[NSArray array]] autorelease]; +} + +- (id)transformedValue:(id)object +{ + return object; +} + +@end + + +// ============================================================================= +#pragma mark - Private concrete class GRMustacheBlockFilter + +@implementation GRMustacheBlockFilter + +- (instancetype)initWithBlock:(id(^)(id value))block +{ + if (block == nil) { + [NSException raise:NSInvalidArgumentException format:@"Can't build a filter with a nil block."]; + } + + self = [self init]; + if (self) { + _block = [block copy]; + } + return self; +} + + +- (void)dealloc +{ + [_block release]; + [super dealloc]; +} + +#pragma mark + +- (id)transformedValue:(id)object +{ + return _block(object); +} + +@end + + +// ============================================================================= +#pragma mark - Private concrete class GRMustacheBlockVariadicFilter + +@implementation GRMustacheBlockVariadicFilter + +- (instancetype)initWithBlock:(id(^)(NSArray *arguments))block arguments:(NSArray *)arguments +{ + if (block == nil) { + [NSException raise:NSInvalidArgumentException format:@"Can't build a filter with a nil block."]; + } + + self = [self init]; + if (self) { + _block = [block copy]; + _arguments = [arguments retain]; + } + return self; +} + +- (void)dealloc +{ + [_block release]; + [_arguments release]; + [super dealloc]; +} + + +#pragma mark + +- (id)transformedValue:(id)object +{ + NSArray *arguments = [_arguments arrayByAddingObject:(object ?: [NSNull null])]; + return _block(arguments); +} + +- (id)filterByCurryingArgument:(id)object +{ + NSArray *arguments = [_arguments arrayByAddingObject:(object ?: [NSNull null])]; + return [[[GRMustacheBlockVariadicFilter alloc] initWithBlock:_block arguments:arguments] autorelease]; +} + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter_private.h b/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter_private.h new file mode 100644 index 0000000..df688c5 --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheFilter_private.h @@ -0,0 +1,64 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +// prevent GRMustacheFilter.h to load +#define GRMUSTACHE_FILTER + +// Documented in GRMustacheFilter.h +@protocol GRMustacheFilter +@required + +// Documented in GRMustacheFilter.h +- (id)transformedValue:(id)object GRMUSTACHE_API_PUBLIC; + +@optional + +/** + * Returns a new filter that uses the _object_ parameter. + * + * Filter currying is involved in `f(a,...)` expressions, filters with more than + * one argument. + * + * The evaluation of `f(a,b)` is implemented as `f(a)(b)`: the filter `f` is + * asked for a curried filter using argument `a`. This curried filter `g` is + * then applied to `b`: + * + * g = f(a) + * f(a,b) = g(b) + */ +- (id)filterByCurryingArgument:(id)object GRMUSTACHE_API_INTERNAL; +@end + + +// Documented in GRMustacheFilter.h +@interface GRMustacheFilter : NSObject + +// Documented in GRMustacheFilter.h ++ (id)filterWithBlock:(id(^)(id value))block GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheFilter.h ++ (id)variadicFilterWithBlock:(id(^)(NSArray *arguments))block GRMUSTACHE_API_PUBLIC; + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheKeyAccess.m b/Pods/GRMustache/src/classes/Rendering/GRMustacheKeyAccess.m new file mode 100644 index 0000000..c0f7fb2 --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheKeyAccess.m @@ -0,0 +1,693 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import +#import "GRMustacheKeyAccess_private.h" +#import "GRMustacheSafeKeyAccess.h" +#import "JRSwizzle.h" + + +#if !defined(NS_BLOCK_ASSERTIONS) +// For testing purpose +BOOL GRMustacheKeyAccessDidCatchNSUndefinedKeyException; +#endif + + +// ============================================================================= +#pragma mark - Safe key access + +static pthread_key_t GRSafeKeysForClassKey; +void freeSafeKeysForClass(void *objects) { + CFRelease((CFMutableDictionaryRef)objects); +} +#define setupSafeKeysForClass() pthread_key_create(&GRSafeKeysForClassKey, freeSafeKeysForClass) +#define getCurrentThreadSafeKeysForClass() (CFMutableDictionaryRef)pthread_getspecific(GRSafeKeysForClassKey) +#define setCurrentThreadSafeKeysForClass(classes) pthread_setspecific(GRSafeKeysForClassKey, classes) + + +// ============================================================================= +#pragma mark - Foundation declarations + +static NSMutableSet *safeMustacheKeysForNSArray; +static NSMutableSet *safeMustacheKeysForNSAttributedString; +static NSMutableSet *safeMustacheKeysForNSData; +static NSMutableSet *safeMustacheKeysForNSDate; +static NSMutableSet *safeMustacheKeysForNSDateComponents; +static NSMutableSet *safeMustacheKeysForNSDecimalNumber; +static NSMutableSet *safeMustacheKeysForNSError; +static NSMutableSet *safeMustacheKeysForNSHashTable; +static NSMutableSet *safeMustacheKeysForNSIndexPath; +static NSMutableSet *safeMustacheKeysForNSIndexSet; +static NSMutableSet *safeMustacheKeysForNSMapTable; +static NSMutableSet *safeMustacheKeysForNSNotification; +static NSMutableSet *safeMustacheKeysForNSException; +static NSMutableSet *safeMustacheKeysForNSNumber; +static NSMutableSet *safeMustacheKeysForNSOrderedSet; +static NSMutableSet *safeMustacheKeysForNSPointerArray; +static NSMutableSet *safeMustacheKeysForNSSet; +static NSMutableSet *safeMustacheKeysForNSString; +static NSMutableSet *safeMustacheKeysForNSURL; +static NSMutableSet *safeMustacheKeysForNSValue; + +static NSSet *safeMustacheKeys_NSArray(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSAttributedString(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSData(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSDate(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSDateComponents(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSDecimalNumber(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSError(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSHashTable(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSIndexPath(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSIndexSet(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSMapTable(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSNotification(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSException(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSNumber(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSOrderedSet(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSPointerArray(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSSet(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSString(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSURL(id self, SEL _cmd); +static NSSet *safeMustacheKeys_NSValue(id self, SEL _cmd); + + +// ============================================================================= +#pragma mark - NSUndefinedKeyException prevention declarations + +@interface NSObject(GRMustacheKeyAccessPreventionOfNSUndefinedKeyException) +- (id)GRMustacheKeyAccessValueForUndefinedKey_NSObject:(NSString *)key; +- (id)GRMustacheKeyAccessValueForUndefinedKey_NSManagedObject:(NSString *)key; +@end; + + +// ============================================================================= +#pragma mark - GRMustacheKeyAccess + +static Class NSOrderedSetClass; +static Class NSManagedObjectClass; + +@interface NSObject(GRMustacheCoreDataMethods) +- (NSDictionary *)propertiesByName; +- (id)entity; +@end + +@implementation GRMustacheKeyAccess + ++ (void)initialize +{ + NSOrderedSetClass = NSClassFromString(@"NSOrderedSet"); + NSManagedObjectClass = NSClassFromString(@"NSManagedObject"); + [self setupSafeKeyAccessForFoundationClasses]; + setupSafeKeysForClass(); +} + ++ (id)valueForMustacheKey:(NSString *)key inObject:(id)object unsafeKeyAccess:(BOOL)unsafeKeyAccess +{ + if (object == nil) { + return nil; + } + + + // Try objectForKeyedSubscript: first (see https://github.com/groue/GRMustache/issues/66:) + + if ([object respondsToSelector:@selector(objectForKeyedSubscript:)]) { + return [object objectForKeyedSubscript:key]; + } + + + // Then try valueForKey: for safe keys + + if (!unsafeKeyAccess && ![self isSafeMustacheKey:key forObject:object]) { + return nil; + } + + + @try { + + // valueForKey: may throw NSUndefinedKeyException, and user may want to + // prevent them. + + if (preventsNSUndefinedKeyException) { + [GRMustacheKeyAccess startPreventingNSUndefinedKeyExceptionFromObject:object]; + } + + // We don't want to use NSArray, NSSet and NSOrderedSet implementation + // of valueForKey:, because they return another collection: see issue + // #21 and "anchored key should not extract properties inside an array" + // test in src/tests/Public/v4.0/GRMustacheSuites/compound_keys.json + // + // Instead, we want the behavior of NSObject's implementation of valueForKey:. + + if ([self objectIsFoundationCollectionWhoseImplementationOfValueForKeyReturnsAnotherCollection:object]) { + return [self valueForMustacheKey:key inFoundationCollectionObject:object]; + } else { + return [object valueForKey:key]; + } + } + + @catch (NSException *exception) { + + // Swallow NSUndefinedKeyException only + + if (![[exception name] isEqualToString:NSUndefinedKeyException]) { + [exception raise]; + } +#if !defined(NS_BLOCK_ASSERTIONS) + else { + // For testing purpose + GRMustacheKeyAccessDidCatchNSUndefinedKeyException = YES; + } +#endif + } + + @finally { + if (preventsNSUndefinedKeyException) { + [GRMustacheKeyAccess stopPreventingNSUndefinedKeyExceptionFromObject:object]; + } + } + + return nil; +} + + +// ============================================================================= +#pragma mark - Foundation collections + ++ (BOOL)objectIsFoundationCollectionWhoseImplementationOfValueForKeyReturnsAnotherCollection:(id)object +{ + if ([object isKindOfClass:[NSArray class]]) { return YES; } + if ([object isKindOfClass:[NSSet class]]) { return YES; } + if (NSOrderedSetClass && [object isKindOfClass:NSOrderedSetClass]) { return YES; } + return NO; +} + ++ (id)valueForMustacheKey:(NSString *)key inFoundationCollectionObject:(id)object +{ + // Ideally, we would use NSObject's implementation for collections, so that + // we can access properties such as `count`, `anyObject`, etc. + // + // And so we did, until [issue #70](https://github.com/groue/GRMustache/issues/70) + // revealed that the direct use of NSObject's imp crashes on arm64: + // + // IMP imp = class_getMethodImplementation([NSObject class], @selector(valueForKey:)); + // return imp(object, @selector(valueForKey:), key); // crash on arm64 + // + // objc_msgSendSuper fails on arm64 as well: + // + // return objc_msgSendSuper( + // &(struct objc_super){ .receiver = object, .super_class = [NSObject class] }, + // @selector(valueForKey:), + // key); // crash on arm64 + // + // So we have to implement NSObject's valueForKey: ourselves. + // + // Quoting Apple documentation: + // https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/SearchImplementation.html + // + // > Default Search Pattern for valueForKey: + // > + // > 1. Searches the class of the receiver for an accessor method whose + // > name matches the pattern get, , or is, in that order. + // + // The remaining of the search pattern goes into aggregates and ivars. Let's + // ignore aggregates (until someone has a need for it), and ivars (since + // they are private). + + NSString *keyWithUppercaseInitial = [NSString stringWithFormat:@"%@%@", + [[key substringToIndex:1] uppercaseString], + [key substringFromIndex:1]]; + NSArray *accessors = [NSArray arrayWithObjects: + [NSString stringWithFormat:@"get%@", keyWithUppercaseInitial], + key, + [NSString stringWithFormat:@"is%@", keyWithUppercaseInitial], + nil]; + + for (NSString *accessor in accessors) { + SEL selector = NSSelectorFromString(accessor); + if ([object respondsToSelector:selector]) { + + // Extract the raw value into a buffer + + NSMethodSignature *methodSignature = [object methodSignatureForSelector:selector]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; + invocation.selector = selector; + [invocation invokeWithTarget:object]; + NSUInteger methodReturnLength = [methodSignature methodReturnLength]; + if (methodReturnLength == 0) { + // no value + return nil; + } else { + void *buffer = malloc(methodReturnLength); + if (buffer == NULL) { + // Allocation failed. + // + // This method is not supposed to allocate any object, so we + // can not behave like failing allocating methods and return + // nil. + // + // So let's raise an exception. + // + // NSMallocException is supposedly obsolete but there are + // evidences it is still used by Foundation: + // http://stackoverflow.com/search?q=NSMallocException + [NSException raise:NSMallocException format:@"Out of memory."]; + } + [invocation getReturnValue:buffer]; + + // Turn the raw value buffer into an object + + id result = nil; + const char *objCType = [methodSignature methodReturnType]; + switch(objCType[0]) { + case 'c': + result = [NSNumber numberWithChar:*(char *)buffer]; + break; + case 'i': + result = [NSNumber numberWithInt:*(int *)buffer]; + break; + case 's': + result = [NSNumber numberWithShort:*(short *)buffer]; + break; + case 'l': + result = [NSNumber numberWithLong:*(long *)buffer]; + break; + case 'q': + result = [NSNumber numberWithLongLong:*(long long *)buffer]; + break; + case 'C': + result = [NSNumber numberWithUnsignedChar:*(unsigned char *)buffer]; + break; + case 'I': + result = [NSNumber numberWithUnsignedInt:*(unsigned int *)buffer]; + break; + case 'S': + result = [NSNumber numberWithUnsignedShort:*(unsigned short *)buffer]; + break; + case 'L': + result = [NSNumber numberWithUnsignedLong:*(unsigned long *)buffer]; + break; + case 'Q': + result = [NSNumber numberWithUnsignedLongLong:*(unsigned long long *)buffer]; + break; + case 'B': + result = [NSNumber numberWithBool:*(_Bool *)buffer]; + break; + case 'f': + result = [NSNumber numberWithFloat:*(float *)buffer]; + break; + case 'd': + result = [NSNumber numberWithDouble:*(double *)buffer]; + break; + case '@': + case '#': + result = *(id *)buffer; + break; + default: + [NSException raise:NSInternalInconsistencyException format:@"Not implemented yet"]; + break; + } + + free(buffer); + return result; + } + } + } + + return nil; +} + + +// ============================================================================= +#pragma mark - Foundation + ++ (void)setupSafeKeyAccessForFoundationClasses +{ + // Safe key access prevents dangerous methods from being accessed by bad + // templates through `valueForKey:`. + // + // By default, only declared properties can be accessed, unless classes + // conform to the GRMustacheSafeKeyAccess protocol. + // + // We want to let users have a liberal use of KVC on Foundation classes: + // `{{# array.count }}`, `{{ dateComponents.year }}`, etc. Those classes + // do not always declare properties for those accessors. + // + // So let's setup safe keys for common Foundation classes, by allowing + // all their non-mutating methods, plus a few safe NSObject methods, + // minus dangerous NSObject methods. + + NSSet *safeMustacheNSObjectKeys = [NSSet setWithObjects: + @"class", + @"superclass", + @"self", + @"description", + @"debugDescription", + nil]; + NSSet *unsafeMustacheNSObjectKeys = [NSSet setWithObjects: + @"init", + @"dealloc", + @"finalize", + @"copy", + @"mutableCopy", + @"retain", + @"release", + @"autorelease", + nil]; + + SEL selector = @selector(safeMustacheKeys); + Protocol *protocol = @protocol(GRMustacheSafeKeyAccess); + struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, YES, NO); + +#define setupSafeKeyAccessForClass(klassName) do {\ +Class klass = NSClassFromString(@#klassName);\ +if (klass) {\ +Class metaKlass = object_getClass(klass);\ +safeMustacheKeysFor ## klassName = [[self allPublicKeysForClass:klass] retain];\ +[safeMustacheKeysFor ## klassName unionSet:safeMustacheNSObjectKeys];\ +[safeMustacheKeysFor ## klassName minusSet:unsafeMustacheNSObjectKeys];\ +class_addMethod(metaKlass, selector, (IMP)safeMustacheKeys_ ## klassName, methodDescription.types);\ +class_addProtocol(klass, protocol);\ +}\ +} while(0); + + setupSafeKeyAccessForClass(NSArray); + setupSafeKeyAccessForClass(NSAttributedString); + setupSafeKeyAccessForClass(NSData); + setupSafeKeyAccessForClass(NSDate); + setupSafeKeyAccessForClass(NSDateComponents); + setupSafeKeyAccessForClass(NSDecimalNumber); + setupSafeKeyAccessForClass(NSError); + setupSafeKeyAccessForClass(NSHashTable); + setupSafeKeyAccessForClass(NSIndexPath); + setupSafeKeyAccessForClass(NSIndexSet); + setupSafeKeyAccessForClass(NSMapTable); + setupSafeKeyAccessForClass(NSNotification); + setupSafeKeyAccessForClass(NSException); + setupSafeKeyAccessForClass(NSNumber); + setupSafeKeyAccessForClass(NSOrderedSet); + setupSafeKeyAccessForClass(NSPointerArray); + setupSafeKeyAccessForClass(NSSet); + setupSafeKeyAccessForClass(NSString); + setupSafeKeyAccessForClass(NSURL); + setupSafeKeyAccessForClass(NSValue); +} + +/** + * Return the set of methods without arguments, up to NSObject, non including NSObject. + */ ++ (NSMutableSet *)allPublicKeysForClass:(Class)klass +{ + NSMutableSet *keys = [NSMutableSet set]; + Class NSObjectClass = [NSObject class]; + while (klass && klass != NSObjectClass) { + unsigned int methodCount; + Method *methods = class_copyMethodList(klass, &methodCount); + for (unsigned int i = 0; i < methodCount; ++i) { + SEL selector = method_getName(methods[i]); + const char *selectorName = sel_getName(selector); + if (selectorName[0] != '_' && selectorName[strlen(selectorName) - 1] != '_' && strstr(selectorName, ":") == NULL) { + [keys addObject:NSStringFromSelector(selector)]; + } + } + free (methods); + klass = class_getSuperclass(klass); + } + + return keys; +} + + +// ============================================================================= +#pragma mark - Safe key access + ++ (BOOL)isSafeMustacheKey:(NSString *)key forObject:(id)object +{ + NSSet *safeKeys = nil; + { + CFMutableDictionaryRef safeKeysForClass = getCurrentThreadSafeKeysForClass(); + if (!safeKeysForClass) { + safeKeysForClass = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks); + setCurrentThreadSafeKeysForClass(safeKeysForClass); + } + + Class klass = [object class]; + safeKeys = (NSSet *)CFDictionaryGetValue(safeKeysForClass, klass); + if (safeKeys == nil) { + if ([klass respondsToSelector:@selector(safeMustacheKeys)]) { + safeKeys = [klass safeMustacheKeys] ?: [NSSet set]; + } else { + NSMutableSet *keys = [self propertyGettersForClass:klass]; + if (NSManagedObjectClass && [object isKindOfClass:NSManagedObjectClass]) { + [keys unionSet:[NSSet setWithArray:[[[object entity] propertiesByName] allKeys]]]; + } + safeKeys = keys; + } + CFDictionarySetValue(safeKeysForClass, klass, safeKeys); + } + } + + return [safeKeys containsObject:key]; +} + ++ (NSMutableSet *)propertyGettersForClass:(Class)klass +{ + NSMutableSet *safeKeys = [NSMutableSet set]; + while (klass) { + // Iterate properties + + unsigned int count; + objc_property_t *properties = class_copyPropertyList(klass, &count); + + for (unsigned int i=0; i +#import "GRMustacheAvailabilityMacros_private.h" + +#if !defined(NS_BLOCK_ASSERTIONS) +/** + * This global variable is used by GRPreventNSUndefinedKeyExceptionAttackTest. + */ +extern BOOL GRMustacheKeyAccessDidCatchNSUndefinedKeyException; +#endif + +/** + * GRMustacheKeyAccess implements all the GRMustache key-fetching logic. + */ +@interface GRMustacheKeyAccess : NSObject + +/** + * Avoids most NSUndefinedException to be raised by the invocation of + * `valueForMustacheKey:inObject:`. + * + * @see valueForMustacheKey:inObject: + */ ++ (void)preventNSUndefinedKeyExceptionAttack GRMUSTACHE_API_INTERNAL; + +/** + * Sends the `objectForKeyedSubscript:` or `valueForKey:` message to object + * with the provided key, and returns the result. + * + * If object responds to `objectForKeyedSubscript:`, `valueForKey:` is not + * invoked. + * + * If `valueForKey:` raise an NSUndefinedKeyException, the method returns nil. + * + * @param key The searched key + * @param object The queried object + * @param unsafeKeyAccess If YES, the `valueForKey:` method will be used + * without any restriction. + * + * @return The value that should be handled by Mustache rendering for a given + * key. + */ ++ (id)valueForMustacheKey:(NSString *)key inObject:(id)object unsafeKeyAccess:(BOOL)unsafeKeyAccess GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.h b/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.h new file mode 100644 index 0000000..f1b526a --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.h @@ -0,0 +1,130 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef GRMUSTACHE_RENDERING +#define GRMUSTACHE_RENDERING + +#import +#import "GRMustacheAvailabilityMacros.h" + +@class GRMustacheContext; +@class GRMustacheTag; + + +// ============================================================================= +#pragma mark - + + +/** + * The protocol for your own objects that perform custom rendering. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/rendering_objects.md + */ +@protocol GRMustacheRendering + +/** + * This method is invoked when the receiver should be rendered by a Mustache + * tag. + * + * It returns three values: the rendering itself, a boolean that says whether + * the rendering is HTML-safe or not, and an eventual error. + * + * Input values are the tag that should be rendered, and the context object that + * represents the current context stack. + * + * Depending on the content type of the currently rendered template, an output + * parameter _HTMLSafe_ set to NO will have the returned string HTML-escaped. + * + * @param tag The tag to be rendered + * @param context A context for rendering inner tags. + * @param HTMLSafe Upon return contains YES if the result is HTML-safe. + * @param error If there is an error performing the rendering, upon return + * contains an NSError object that describes the problem. + * + * @return The rendering of the receiver for the given tag, in the given + * context. + * + * @see GRMustacheTag + * @see GRMustacheContext + * @see GRMustacheContentType + * + * @since v6.0 + */ +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag + context:(GRMustacheContext *)context + HTMLSafe:(BOOL *)HTMLSafe + error:(NSError **)error AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; +@end + + +// ============================================================================= +#pragma mark - GRMustacheRendering + +/** + * The GRMustacheRendering class helps building rendering objects without + * writing a custom class that conforms to the GRMustacheRendering protocol. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/rendering_objects.md + * + * @see GRMustacheRendering protocol + * + * @since v7.0 + */ +@interface GRMustacheRendering : NSObject + +//////////////////////////////////////////////////////////////////////////////// +/// @name Creating Rendering Objects +//////////////////////////////////////////////////////////////////////////////// + +/** + * Returns a rendering object that is able to render the argument _object_ for + * the various Mustache tags. + * + * @param object An object. + * + * @return A rendering object able to render the argument. + * + * @see GRMustacheRendering protocol + * + * @since v7.0 + */ ++ (id)renderingObjectForObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Returns a rendering object that renders with the provided block. + * + * @param renderingBlock A block that follows the semantics of the + * renderForMustacheTag:context:HTMLSafe:error: method + * defined by the GRMustacheRendering protocol. See the + * documentation of this method. + * + * @return A rendering object + * + * @see GRMustacheRendering protocol + * + * @since v7.0 + */ ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))renderingBlock AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end + +#endif diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.m b/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.m new file mode 100644 index 0000000..ed7a138 --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering.m @@ -0,0 +1,608 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import +#import "GRMustacheRendering_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheConfiguration_private.h" +#import "GRMustacheContext_private.h" +#import "GRMustacheError.h" +#import "GRMustacheTemplateRepository_private.h" +#import "GRMustacheBuffer_private.h" + + +// ============================================================================= +#pragma mark - Rendering declarations + + +// GRMustacheNilRendering renders for nil + +@interface GRMustacheNilRendering : NSObject +@end +static GRMustacheNilRendering *nilRendering; + + +// GRMustacheBlockRendering renders with a block + +@interface GRMustacheBlockRendering : NSObject { +@private + NSString *(^_renderingBlock)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +} +- (instancetype)initWithRenderingBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))renderingBlock; +@end + + +// NSNull, NSNumber, NSString, NSObject, NSFastEnumeration rendering + +typedef NSString *(*GRMustacheRenderIMP)(id self, SEL _cmd, GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderGeneric(id self, SEL _cmd, GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); + +typedef NSString *(*GRMustacheRenderWithIterationSupportIMP)(id self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportGeneric(id self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportNSNull(NSNull *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportNSNumber(NSNumber *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportNSString(NSString *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportNSObject(NSObject *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); +static NSString *GRMustacheRenderWithIterationSupportNSFastEnumeration(id self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error); + +typedef BOOL (*GRMustacheBoolValueIMP)(id self, SEL _cmd); +static BOOL GRMustacheBoolValueGeneric(id self, SEL _cmd); +static BOOL GRMustacheBoolValueNSNull(NSNull *self, SEL _cmd); +static BOOL GRMustacheBoolValueNSNumber(NSNumber *self, SEL _cmd); +static BOOL GRMustacheBoolValueNSString(NSString *self, SEL _cmd); +static BOOL GRMustacheBoolValueNSObject(NSObject *self, SEL _cmd); +static BOOL GRMustacheBoolValueNSFastEnumeration(id self, SEL _cmd); + + +// ============================================================================= +#pragma mark - Current Template Repository + +static pthread_key_t GRCurrentTemplateRepositoryStackKey; +void freeCurrentTemplateRepositoryStack(void *objects) { + [(NSMutableArray *)objects release]; +} +#define setupCurrentTemplateRepositoryStack() pthread_key_create(&GRCurrentTemplateRepositoryStackKey, freeCurrentTemplateRepositoryStack) +#define getCurrentThreadCurrentTemplateRepositoryStack() (NSMutableArray *)pthread_getspecific(GRCurrentTemplateRepositoryStackKey) +#define setCurrentThreadCurrentTemplateRepositoryStack(classes) pthread_setspecific(GRCurrentTemplateRepositoryStackKey, classes) + + +// ============================================================================= +#pragma mark - Current Content Type + +static pthread_key_t GRCurrentContentTypeStackKey; +void freeCurrentContentTypeStack(void *objects) { + [(NSMutableArray *)objects release]; +} +#define setupCurrentContentTypeStack() pthread_key_create(&GRCurrentContentTypeStackKey, freeCurrentContentTypeStack) +#define getCurrentThreadCurrentContentTypeStack() (NSMutableArray *)pthread_getspecific(GRCurrentContentTypeStackKey) +#define setCurrentThreadCurrentContentTypeStack(classes) pthread_setspecific(GRCurrentContentTypeStackKey, classes) + + +// ============================================================================= +#pragma mark - GRMustacheRendering + +@implementation GRMustacheRendering + ++ (void)initialize +{ + setupCurrentTemplateRepositoryStack(); + setupCurrentContentTypeStack(); + + nilRendering = [[GRMustacheNilRendering alloc] init]; + + // We could have declared categories on NSNull, NSNumber, NSString and + // NSDictionary. + // + // We do not, because many GRMustache users use the static library, and + // we don't want to force them adding the `-ObjC` option to their + // target's "Other Linker Flags" (which is required for code declared by + // categories to be loaded). + // + // Instead, dynamically alter the classes whose rendering implementation + // is already known. + // + // Other classes will be dynamically attached their rendering implementation + // in the GRMustacheRenderWithIterationSupportGeneric implementation + // attached to NSObject. + [self registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSNull boolValueIMP:GRMustacheBoolValueNSNull forClass:[NSNull class]]; + [self registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSNumber boolValueIMP:GRMustacheBoolValueNSNumber forClass:[NSNumber class]]; + [self registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSString boolValueIMP:GRMustacheBoolValueNSString forClass:[NSString class]]; + [self registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSObject boolValueIMP:GRMustacheBoolValueNSObject forClass:[NSDictionary class]]; + [self registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportGeneric boolValueIMP:GRMustacheBoolValueGeneric forClass:[NSObject class]]; + + // Besides, provide all objects the ability to render as an enumeration item + // or not through GRMustacheRenderGeneric: + [self registerRenderIMP:GRMustacheRenderGeneric forClass:[NSObject class]]; + +} + ++ (id)renderingObjectForObject:(id)object +{ + // All objects but nil know how to render (see setupRendering). + return object ?: nilRendering; +} + ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))renderingBlock +{ + return [[[GRMustacheBlockRendering alloc] initWithRenderingBlock:renderingBlock] autorelease]; +} + + +#pragma mark - Current Template Repository + ++ (void)pushCurrentTemplateRepository:(GRMustacheTemplateRepository *)templateRepository +{ + NSMutableArray *stack = getCurrentThreadCurrentTemplateRepositoryStack(); + if (!stack) { + stack = [[NSMutableArray alloc] init]; + setCurrentThreadCurrentTemplateRepositoryStack(stack); + } + [stack addObject:templateRepository]; +} + ++ (void)popCurrentTemplateRepository +{ + NSMutableArray *stack = getCurrentThreadCurrentTemplateRepositoryStack(); + NSAssert(stack, @"Missing currentTemplateRepositoryStack"); + NSAssert(stack.count > 0, @"Empty currentTemplateRepositoryStack"); + [stack removeLastObject]; +} + ++ (GRMustacheTemplateRepository *)currentTemplateRepository +{ + NSMutableArray *stack = getCurrentThreadCurrentTemplateRepositoryStack(); + return [stack lastObject]; +} + + +#pragma mark - Current Content Type + ++ (void)pushCurrentContentType:(GRMustacheContentType)contentType +{ + NSMutableArray *stack = getCurrentThreadCurrentContentTypeStack(); + if (!stack) { + stack = [[NSMutableArray alloc] init]; + setCurrentThreadCurrentContentTypeStack(stack); + } + [stack addObject:[NSNumber numberWithUnsignedInteger:contentType]]; +} + ++ (void)popCurrentContentType +{ + NSMutableArray *stack = getCurrentThreadCurrentContentTypeStack(); + NSAssert(stack, @"Missing currentContentTypeStack"); + NSAssert(stack.count > 0, @"Empty currentContentTypeStack"); + [stack removeLastObject]; +} + ++ (GRMustacheContentType)currentContentType +{ + NSMutableArray *stack = getCurrentThreadCurrentContentTypeStack(); + if (stack.count > 0) { + return [(NSNumber *)[stack lastObject] unsignedIntegerValue]; + } + return ([self currentTemplateRepository].configuration ?: [GRMustacheConfiguration defaultConfiguration]).contentType; +} + + +#pragma mark - Private + +/** + * Have the class _aClass_ conform to the + * GRMustacheRenderingWithIterationSupport protocol. + * + * @param renderIMP the implementation of the + * renderForMustacheTag:asEnumerationItem:context:HTMLSafe:error: + * method. + * @param boolValueIMP the implementation of the mustacheBoolValue method. + * @param aClass the class to modify. + */ ++ (void)registerRenderWithIterationSupportIMP:(GRMustacheRenderWithIterationSupportIMP)renderIMP boolValueIMP:(GRMustacheBoolValueIMP)boolValueIMP forClass:(Class)klass +{ + Protocol *protocol = @protocol(GRMustacheRenderingWithIterationSupport); + + // Add method implementations + + { + SEL selector = @selector(renderForMustacheTag:asEnumerationItem:context:HTMLSafe:error:); + struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES); + class_addMethod(klass, selector, (IMP)renderIMP, methodDescription.types); + } + + { + SEL selector = @selector(mustacheBoolValue); + struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES); + class_addMethod(klass, selector, (IMP)boolValueIMP, methodDescription.types); + } + + // Add protocol conformance + class_addProtocol(klass, protocol); +} + +/** + * Have the class _aClass_ conform to the GRMustacheRendering protocol. + * + * @param renderIMP the implementation of the + * renderForMustacheTag:context:HTMLSafe:error: method. + * @param aClass the class to modify. + */ ++ (void)registerRenderIMP:(GRMustacheRenderIMP)renderIMP forClass:(Class)klass +{ + Protocol *protocol = @protocol(GRMustacheRendering); + + // Add method implementations + + { + SEL selector = @selector(renderForMustacheTag:context:HTMLSafe:error:); + struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES); + class_addMethod(klass, selector, (IMP)renderIMP, methodDescription.types); + } + + // Add protocol conformance + class_addProtocol(klass, protocol); +} + +@end + + +// ============================================================================= +#pragma mark - Rendering Implementations + +@implementation GRMustacheNilRendering + +- (BOOL)mustacheBoolValue +{ + return NO; +} + +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + return [self renderForMustacheTag:tag asEnumerationItem:NO context:context HTMLSafe:HTMLSafe error:error]; +} + +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag asEnumerationItem:(BOOL)enumerationItem context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ nil }} + return @""; + + case GRMustacheTagTypeSection: + // {{# nil }}...{{/}} + // {{^ nil }}...{{/}} + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } +} + +@end + + +@implementation GRMustacheBlockRendering + +- (void)dealloc +{ + [_renderingBlock release]; + [super dealloc]; +} + +- (instancetype)initWithRenderingBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))renderingBlock +{ + if (renderingBlock == nil) { + [NSException raise:NSInvalidArgumentException format:@"Can't build a rendering object with a nil rendering block."]; + } + + self = [super init]; + if (self) { + _renderingBlock = [renderingBlock copy]; + } + return self; +} + +- (BOOL)mustacheBoolValue +{ + return YES; +} + +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + return _renderingBlock(tag, context, HTMLSafe, error); +} + +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag asEnumerationItem:(BOOL)enumerationItem context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + return _renderingBlock(tag, context, HTMLSafe, error); +} + +@end + + +static BOOL GRMustacheBoolValueGeneric(id self, SEL _cmd) +{ + // Self doesn't know (yet) its mustache boolean value + + Class klass = object_getClass(self); + if ([self respondsToSelector:@selector(countByEnumeratingWithState:objects:count:)]) + { + // Future invocations will use GRMustacheBoolValueNSFastEnumeration + [GRMustacheRendering registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSFastEnumeration boolValueIMP:GRMustacheBoolValueNSFastEnumeration forClass:klass]; + return GRMustacheBoolValueNSFastEnumeration(self, _cmd); + } + + if (klass != [NSObject class]) + { + // Future invocations will use GRMustacheRenderNSObject + [GRMustacheRendering registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSObject boolValueIMP:GRMustacheBoolValueNSObject forClass:klass]; + } + + return GRMustacheBoolValueNSObject(self, _cmd); +} + +static NSString *GRMustacheRenderGeneric(id self, SEL _cmd, GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + return [self renderForMustacheTag:tag asEnumerationItem:NO context:context HTMLSafe:HTMLSafe error:error]; +} + +static NSString *GRMustacheRenderWithIterationSupportGeneric(id self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + // Self doesn't know (yet) how to render as an enumeration item + + Class klass = object_getClass(self); + if ([self respondsToSelector:@selector(countByEnumeratingWithState:objects:count:)]) + { + // Future invocations will use GRMustacheRenderNSFastEnumeration + [GRMustacheRendering registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSFastEnumeration boolValueIMP:GRMustacheBoolValueNSFastEnumeration forClass:klass]; + return GRMustacheRenderWithIterationSupportNSFastEnumeration(self, _cmd, tag, enumerationItem, context, HTMLSafe, error); + } + + if (klass != [NSObject class]) + { + // Future invocations will use GRMustacheRenderWithIterationSupportNSObject + [GRMustacheRendering registerRenderWithIterationSupportIMP:GRMustacheRenderWithIterationSupportNSObject boolValueIMP:GRMustacheBoolValueNSObject forClass:klass]; + } + + return GRMustacheRenderWithIterationSupportNSObject(self, _cmd, tag, enumerationItem, context, HTMLSafe, error); +} + +static BOOL GRMustacheBoolValueNSNull(NSNull *self, SEL _cmd) +{ + return NO; +} + +static NSString *GRMustacheRenderWithIterationSupportNSNull(NSNull *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ null }} + return @""; + + case GRMustacheTagTypeSection: + if (enumerationItem) { + context = [context newContextByAddingObject:self]; + NSString *rendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + [context release]; + return rendering; + } else { + // {{^ null }}...{{/}} + // {{# null }}...{{/}} + + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } + } +} + +static BOOL GRMustacheBoolValueNSNumber(NSNumber *self, SEL _cmd) +{ + return [self boolValue]; +} + +static NSString *GRMustacheRenderWithIterationSupportNSNumber(NSNumber *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ number }} + if (HTMLSafe != NULL) { + *HTMLSafe = NO; + } + return [self description]; + + case GRMustacheTagTypeSection: + if (enumerationItem) { + context = [context newContextByAddingObject:self]; + NSString *rendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + [context release]; + return rendering; + } else { + // {{^ number }}...{{/}} + // {{# number }}...{{/}} + // + // janl/mustache.js and defunkt/mustache don't push bools in the + // context stack. Follow their path, and avoid the creation of a + // useless context nobody cares about. + // + // GRMustache 7.2.0 broke this behavior (see issue + // https://github.com/groue/GRMustache/issues/83). This behavior + // must stay! + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } + } +} + +static BOOL GRMustacheBoolValueNSString(NSString *self, SEL _cmd) +{ + return (self.length > 0); +} + +static NSString *GRMustacheRenderWithIterationSupportNSString(NSString *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ string }} + if (HTMLSafe != NULL) { + *HTMLSafe = NO; + } + return self; + + case GRMustacheTagTypeSection: + if (tag.isInverted) { + // {{^ number }}...{{/}} + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } else { + // {{# string }}...{{/}} + context = [context newContextByAddingObject:self]; + NSString *rendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + [context release]; + return rendering; + } + } +} + +static BOOL GRMustacheBoolValueNSObject(NSObject *self, SEL _cmd) +{ + return YES; +} + +static NSString *GRMustacheRenderWithIterationSupportNSObject(NSObject *self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ object }} + if (HTMLSafe != NULL) { + *HTMLSafe = NO; + } + return [self description]; + + case GRMustacheTagTypeSection: + // {{# object }}...{{/}} + // {{^ object }}...{{/}} + context = [context newContextByAddingObject:self]; + NSString *rendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + [context release]; + return rendering; + } +} + +static BOOL GRMustacheBoolValueNSFastEnumeration(id self, SEL _cmd) +{ + for (id _ __attribute__((unused)) in self) { + return YES; + } + return NO; +} + +static NSString *GRMustacheRenderWithIterationSupportNSFastEnumeration(id self, SEL _cmd, GRMustacheTag *tag, BOOL enumerationItem, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) +{ + if (enumerationItem) { + context = [context newContextByAddingObject:self]; + NSString *rendering = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + [context release]; + return rendering; + } + + // {{ list }} + // {{# list }}...{{/}} + // {{^ list }}...{{/}} + + BOOL success = YES; + BOOL bufferCreated = NO; + GRMustacheBuffer buffer; + BOOL anyItemHTMLSafe = NO; + BOOL anyItemHTMLUnsafe = NO; + + for (id item in self) { + if (!bufferCreated) { + buffer = GRMustacheBufferCreate(1024); + bufferCreated = YES; + } + @autoreleasepool { + // Render item + + BOOL itemHTMLSafe = NO; // always assume unsafe rendering + NSError *renderingError = nil; + NSString *rendering = [[GRMustacheRendering renderingObjectForObject:item] renderForMustacheTag:tag asEnumerationItem:YES context:context HTMLSafe:&itemHTMLSafe error:&renderingError]; + + if (!rendering) { + if (!renderingError) { + // Rendering is nil, but rendering error is not set. + // + // Assume a rendering object coded by a lazy programmer, + // whose intention is to render nothing. + + rendering = @""; + } else { + if (error != NULL) { + // make sure error is not released by autoreleasepool + *error = renderingError; + [*error retain]; + } + success = NO; + break; + } + } + + // check consistency of HTML escaping + + if (itemHTMLSafe) { + anyItemHTMLSafe = YES; + if (anyItemHTMLUnsafe) { + [NSException raise:GRMustacheRenderingException format:@"Inconsistant HTML escaping of items in enumeration"]; + } + } else { + anyItemHTMLUnsafe = YES; + if (anyItemHTMLSafe) { + [NSException raise:GRMustacheRenderingException format:@"Inconsistant HTML escaping of items in enumeration"]; + } + } + + // appending the rendering to the buffer + + GRMustacheBufferAppendString(&buffer, rendering); + } + } + + if (!success) { + if (error != NULL) [*error autorelease]; + GRMustacheBufferRelease(&buffer); + return nil; + } + + if (bufferCreated) { + // Non-empty list + + if (HTMLSafe != NULL) { + *HTMLSafe = !anyItemHTMLUnsafe; + } + return GRMustacheBufferGetStringAndRelease(&buffer); + } else { + // Empty list + + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ emptyList }} + return @""; + + case GRMustacheTagTypeSection: + // {{^ emptyList }}...{{/}} + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } + } +} diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine.m b/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine.m new file mode 100644 index 0000000..df7e4f2 --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine.m @@ -0,0 +1,352 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheRenderingEngine_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheSectionTag_private.h" +#import "GRMustacheVariableTag_private.h" +#import "GRMustacheExpression_private.h" +#import "GRMustacheContext_private.h" +#import "GRMustacheRendering_private.h" +#import "GRMustacheTranslateCharacters_private.h" +#import "GRMustacheInheritablePartialNode_private.h" +#import "GRMustacheInheritableSectionNode_private.h" +#import "GRMustachePartialNode_private.h" +#import "GRMustacheTextNode_private.h" +#import "GRMustacheTagDelegate.h" +#import "GRMustacheExpressionInvocation_private.h" + +@interface GRMustacheRenderingEngine() +@end + +static pthread_key_t GRCurrentExpressionInvocationKey; +void freeCurrentExpressionInvocation(void *object) { + [(GRMustacheExpressionInvocation *)object release]; +} +#define setupCurrentExpressionInvocation() pthread_key_create(&GRCurrentExpressionInvocationKey, freeCurrentExpressionInvocation) +#define getCurrentThreadCurrentExpressionInvocation() (GRMustacheExpressionInvocation *)pthread_getspecific(GRCurrentExpressionInvocationKey) +#define setCurrentThreadCurrentExpressionInvocation(object) pthread_setspecific(GRCurrentExpressionInvocationKey, object) +static inline GRMustacheExpressionInvocation *currentThreadCurrentExpressionInvocation() { + GRMustacheExpressionInvocation *expressionInvocation = getCurrentThreadCurrentExpressionInvocation(); + if (!expressionInvocation) { + expressionInvocation = [[GRMustacheExpressionInvocation alloc] init]; + setCurrentThreadCurrentExpressionInvocation(expressionInvocation); + } + return expressionInvocation; +} + + +@implementation GRMustacheRenderingEngine + ++ (void)initialize +{ + setupCurrentExpressionInvocation(); +} + ++ (instancetype)renderingEngineWithContentType:(GRMustacheContentType)contentType context:(GRMustacheContext *)context +{ + return [[[self alloc] initWithContentType:contentType context:context] autorelease]; +} + +- (NSString *)renderTemplateAST:(GRMustacheTemplateAST *)templateAST HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + _buffer = GRMustacheBufferCreate(1024); + + NSString *result = nil; + if ([self visitTemplateAST:templateAST error:error]) { + if (HTMLSafe) { + *HTMLSafe = (_contentType == GRMustacheContentTypeHTML); + } + result = GRMustacheBufferGetString(&_buffer); + } + + GRMustacheBufferRelease(&_buffer); + + return result; +} + + +#pragma mark - AST Nodes + +- (BOOL)visitTemplateAST:(GRMustacheTemplateAST *)templateAST error:(NSError **)error +{ + GRMustacheContentType ASTContentType = templateAST.contentType; + + if (_contentType != ASTContentType) + { + // Render separately... + + GRMustacheRenderingEngine *renderingEngine = [[[GRMustacheRenderingEngine alloc] initWithContentType:ASTContentType context:_context] autorelease]; + BOOL HTMLSafe; + NSString *rendering = [renderingEngine renderTemplateAST:templateAST HTMLSafe:&HTMLSafe error:error]; + if (!rendering) { + return NO; + } + + // ... and escape if needed + + if (_contentType == GRMustacheContentTypeHTML && !HTMLSafe) { + rendering = GRMustacheTranslateHTMLCharacters(rendering); + } + GRMustacheBufferAppendString(&_buffer, rendering); + return YES; + } + else + { + [GRMustacheRendering pushCurrentContentType:ASTContentType]; + BOOL success = [self visitTemplateASTNodes:templateAST.templateASTNodes error:error]; + [GRMustacheRendering popCurrentContentType]; + return success; + } +} + +- (BOOL)visitInheritablePartialNode:(GRMustacheInheritablePartialNode *)inheritablePartialNode error:(NSError **)error +{ + GRMustacheContext *context = _context; + _context = [_context contextByAddingInheritablePartialNode:inheritablePartialNode]; + BOOL success = [self visitPartialNode:inheritablePartialNode.partialNode error:error]; + _context = context; + return success; +} + +- (BOOL)visitInheritableSectionNode:(GRMustacheInheritableSectionNode *)inheritableSectionNode error:(NSError **)error +{ + return [self visitTemplateAST:inheritableSectionNode.templateAST error:error]; +} + +- (BOOL)visitPartialNode:(GRMustachePartialNode *)partialNode error:(NSError **)error +{ + return [self visitTemplateAST:partialNode.templateAST error:error]; +} + +- (BOOL)visitVariableTag:(GRMustacheVariableTag *)variableTag error:(NSError **)error +{ + return [self visitTag:variableTag expression:variableTag.expression escapesHTML:variableTag.escapesHTML error:error]; +} + +- (BOOL)visitSectionTag:(GRMustacheSectionTag *)sectionTag error:(NSError **)error +{ + return [self visitTag:sectionTag expression:sectionTag.expression escapesHTML:YES error:error]; +} + +- (BOOL)visitTextNode:(GRMustacheTextNode *)textNode error:(NSError **)error +{ + GRMustacheBufferAppendString(&_buffer, textNode.text); + return YES; +} + + +#pragma mark - Private + +- (instancetype)initWithContentType:(GRMustacheContentType)contentType context:(GRMustacheContext *)context +{ + NSAssert(context, @"Invalid context:nil"); + + self = [super init]; + if (self) { + _contentType = contentType; + _context = context; + } + return self; +} + +- (BOOL)visitTag:(GRMustacheTag *)tag expression:(GRMustacheExpression *)expression escapesHTML:(BOOL)escapesHTML error:(NSError **)error +{ + BOOL success = YES; + + @autoreleasepool { + + GRMustacheContext *context = _context; + + // Evaluate expression + + GRMustacheExpressionInvocation *expressionInvocation = currentThreadCurrentExpressionInvocation(); + expressionInvocation.expression = expression; + expressionInvocation.context = context; + if (![expressionInvocation invokeReturningError:error]) { + + // Error + + if (error != NULL) { + [*error retain]; // retain error so that it survives the @autoreleasepool block + } + + success = NO; + + } else { + + id value = expressionInvocation.value; + BOOL valueIsProtected = expressionInvocation.valueIsProtected; + + // Hide value if it is protected + if (valueIsProtected) { + // Object is protected: it may enter the context stack, and provide + // value for `.` and `.name`. However, it must not expose its keys. + // + // The goal is to have `{{ safe.name }}` and `{{#safe}}{{.name}}{{/safe}}` + // work, but not `{{#safe}}{{name}}{{/safe}}`. + // + // Rationale: + // + // Let's look at `{{#safe}}{{#hacker}}{{name}}{{/hacker}}{{/safe}}`: + // + // The protected context stack contains the "protected root": + // { safe : { name: "important } }. + // + // Since the user has used the key `safe`, he expects `name` to be + // safe as well, even if `hacker` has defined its own `name`. + // + // So we need to have `name` come from `safe`, not from `hacker`. + // We should thus start looking in `safe` first. But `safe` was + // not initially in the protected context stack. Only the protected + // root was. Hence somebody had `safe` in the protected context + // stack. + // + // Who has objects enter the context stack? Rendering objects do. So + // rendering objects have to know that values are protected or not, + // and choose the correct bucket accordingly. + // + // Who can write his own rendering objects? The end user does. So + // the end user must carefully read a documentation about safety, + // and then carefully code his rendering objects so that they + // conform to this safety notice. + // + // Of course this is not what we want. So `name` can not be + // protected. Since we don't want to let the user think he is data + // is given protected when it is not, we prevent this whole pattern, and + // forbid `{{#safe}}{{name}}{{/safe}}`. + context = [context contextByAddingHiddenObject:value]; + } + + + // Rendered value hooks + + NSArray *tagDelegateStack = [context tagDelegateStack]; + for (id tagDelegate in [tagDelegateStack reverseObjectEnumerator]) { // willRenderObject: from top to bottom + if ([tagDelegate respondsToSelector:@selector(mustacheTag:willRenderObject:)]) { + value = [tagDelegate mustacheTag:tag willRenderObject:value]; + } + } + + + // Render value + + id renderingObject = [GRMustacheRendering renderingObjectForObject:value]; + NSString *rendering = nil; + NSError *renderingError = nil; // Default nil, so that we can help lazy coders who return nil as a valid rendering. + BOOL HTMLSafe = NO; // Default NO, so that we assume unsafe rendering from lazy coders who do not explicitly set it. + switch (tag.type) { + case GRMustacheTagTypeVariable: + rendering = [renderingObject renderForMustacheTag:tag context:context HTMLSafe:&HTMLSafe error:&renderingError]; + break; + + case GRMustacheTagTypeSection: { + // Section rendering depends on the boolean value of the + // rendering object. + // + // Despite the mustacheBoolValue method being declared + // optional by the GRMustacheRendering protocol (for API + // compatibility with GRMustache <= 7.1), the method is + // always implemented, with YES as a default value. + // + // See +[GRMustacheRendering initialize] + BOOL boolValue = [renderingObject mustacheBoolValue]; + if (!tag.isInverted != !boolValue) { + rendering = [renderingObject renderForMustacheTag:tag context:context HTMLSafe:&HTMLSafe error:&renderingError]; + } else { + rendering = @""; + } + } break; + } + + if (!rendering && !renderingError) + { + // Rendering is nil, but rendering error is not set. + // + // Assume a rendering object coded by a lazy programmer, whose + // intention is to render nothing. + + rendering = @""; + } + + + // Finish + + if (rendering) + { + // Render + + if ((_contentType == GRMustacheContentTypeHTML) && !HTMLSafe && escapesHTML) { + rendering = GRMustacheTranslateHTMLCharacters(rendering); + } + GRMustacheBufferAppendString(&_buffer, rendering); + + + // Post-rendering hooks + + for (id tagDelegate in tagDelegateStack) { // didRenderObject: from bottom to top + if ([tagDelegate respondsToSelector:@selector(mustacheTag:didRenderObject:as:)]) { + [tagDelegate mustacheTag:tag didRenderObject:value as:rendering]; + } + } + } + else + { + // Error + + if (error != NULL) { + *error = [renderingError retain]; // retain error so that it survives the @autoreleasepool block + } + success = NO; + + + // Post-error hooks + + for (id tagDelegate in tagDelegateStack) { // didFailRenderingObject: from bottom to top + if ([tagDelegate respondsToSelector:@selector(mustacheTag:didFailRenderingObject:withError:)]) { + [tagDelegate mustacheTag:tag didFailRenderingObject:value withError:renderingError]; + } + } + } + } + } + + if (!success && error) [*error autorelease]; // the error has been retained inside the @autoreleasepool block + return success; +} + +- (BOOL)visitTemplateASTNodes:(NSArray *)templateASTNodes error:(NSError **)error +{ + for (id ASTNode in templateASTNodes) { + ASTNode = [_context resolveTemplateASTNode:ASTNode]; + if (![ASTNode acceptTemplateASTVisitor:self error:error]) { + return NO; + } + } + + return YES; +} + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine_private.h b/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine_private.h new file mode 100644 index 0000000..1b326c5 --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheRenderingEngine_private.h @@ -0,0 +1,53 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheContentType.h" +#import "GRMustacheBuffer_private.h" + +@class GRMustacheContext; +@class GRMustacheSectionTag; +@class GRMustacheExpressionInvocation; +@class GRMustacheTemplateAST; + +/** + * TODO + */ +@interface GRMustacheRenderingEngine : NSObject { +@private + GRMustacheBuffer _buffer; + GRMustacheContentType _contentType; + GRMustacheContext *_context; +} + +/** + * TODO + */ +- (NSString *)renderTemplateAST:(GRMustacheTemplateAST *)templateAST HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +/** + * TODO + */ ++ (instancetype)renderingEngineWithContentType:(GRMustacheContentType)contentType context:(GRMustacheContext *)context GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering_private.h b/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering_private.h new file mode 100644 index 0000000..9ff0b29 --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheRendering_private.h @@ -0,0 +1,157 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" +#import "GRMustacheContentType.h" + +// prevent GRMustacheFilter.h to load +#define GRMUSTACHE_RENDERING + + +@class GRMustacheContext; +@class GRMustacheTag; +@class GRMustacheTemplateRepository; + + +// ============================================================================= +#pragma mark - + + +// Documented in GRMustacheRendering.h +@protocol GRMustacheRendering +@required + +// Documented in GRMustacheRendering.h +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag + context:(GRMustacheContext *)context + HTMLSafe:(BOOL *)HTMLSafe + error:(NSError **)error GRMUSTACHE_API_PUBLIC; + +@optional + +/** + * The boolean value of the rendering object. + * + * A YES boolean value triggers the rendering of {{#section}}...{{/section}} + * tags, and avoids the rendering of inverted {{^section}}...{{/section}} tags. + * + * A NO boolean value avoids the rendering of {{#section}}...{{/section}} + * tags, and triggers the rendering of inverted {{^section}}...{{/section}} tags. + * + * When this method is not provided, the rendering object is assumed to be + * true. + */ +@property (nonatomic, readonly) BOOL mustacheBoolValue GRMUSTACHE_API_INTERNAL; + +@end + + +// ============================================================================= +#pragma mark - + +/** + * The GRMustacheRenderingWithIterationSupport protocol is a private extension + * to the public GRMustacheRendering protocol. + * + * Objects conforming to this protocol can have a different rendering when + * they render as an enumeration item. + * + * Use cases are: + * + * - An NSNumber does not enter the context stack when it renders a + * section, as in {{# 1 }}...{{/}}. + * + * - An NSNumber does enter the context stack when it renders as an enumeration + * item, as in {{# [0,1,2] }}...{{/}}. + * + * - An enumerable object renders all of its items when it renders a + * section, as in {{# [a,b,c] }}...{{/}}. + * + * - An enumerable object have itself enter the context stack when it renders as + * an enumeration item, as in {{# [[a,b,c],[d,e,f]] }}...{{/}}. + */ +@protocol GRMustacheRenderingWithIterationSupport +@required + +/** + * This method is invoked when the receiver should be rendered by a Mustache + * tag. + * + * It returns three values: the rendering itself, a boolean that says whether + * the rendering is HTML-safe or not, and an eventual error. + * + * Input values are the tag that should be rendered, the context object that + * represents the current context stack, and whether the object renders as an + * enumeratiom item or not. + * + * Depending on the content type of the currently rendered template, an output + * parameter _HTMLSafe_ set to NO will have the returned string HTML-escaped. + * + * @param tag The tag to be rendered + * @param enumerationItem YES if the receiver renders as an enumeration item. + * @param context A context for rendering inner tags. + * @param HTMLSafe Upon return contains YES if the result is HTML-safe. + * @param error If there is an error performing the rendering, upon + * return contains an NSError object that describes the + * problem. + * + * @return The rendering of the receiver. + * + * @see GRMustacheTag + * @see GRMustacheContext + * @see GRMustacheContentType + * + * @since v6.0 + */ +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag + asEnumerationItem:(BOOL)enumerationItem + context:(GRMustacheContext *)context + HTMLSafe:(BOOL *)HTMLSafe + error:(NSError **)error GRMUSTACHE_API_INTERNAL; + +@end + + + +// ============================================================================= +#pragma mark - GRMustacheRendering + +// Documented in GRMustacheRendering.h +@interface GRMustacheRendering : NSObject + +// Documented in GRMustacheRendering.h ++ (id)renderingObjectForObject:(id)object GRMUSTACHE_API_PUBLIC; + +// Documented in GRMustacheRendering.h ++ (id)renderingObjectWithBlock:(NSString *(^)(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error))renderingBlock GRMUSTACHE_API_PUBLIC; + ++ (void)pushCurrentTemplateRepository:(GRMustacheTemplateRepository *)templateRepository GRMUSTACHE_API_INTERNAL; ++ (void)popCurrentTemplateRepository GRMUSTACHE_API_INTERNAL; ++ (GRMustacheTemplateRepository *)currentTemplateRepository GRMUSTACHE_API_INTERNAL; + ++ (void)pushCurrentContentType:(GRMustacheContentType)contentType GRMUSTACHE_API_INTERNAL; ++ (void)popCurrentContentType GRMUSTACHE_API_INTERNAL; ++ (GRMustacheContentType)currentContentType GRMUSTACHE_API_INTERNAL; + +@end + diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheSafeKeyAccess.h b/Pods/GRMustache/src/classes/Rendering/GRMustacheSafeKeyAccess.h new file mode 100644 index 0000000..caca227 --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheSafeKeyAccess.h @@ -0,0 +1,54 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" + + +/** + * Your data classes should conform to the GRMustacheSafeKeyAccess protocol + * to filter the keys that can be accessed by GRMustache templates. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/runtime/security.md + */ +@protocol GRMustacheSafeKeyAccess + +/** + * List the name of the keys GRMustache can access on this class using the + * `valueForKey:` method. + * + * When objects do not respond to this method, only declared properties can be + * accessed. All properties of Core Data NSManagedObjects are also accessible, + * even without property declaration. + * + * This method is not used for objects responding to `objectForKeyedSubscript:`. + * For those objects, all keys are accessible from templates. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/security.md + * + * @return The set of accessible keys on the class. + * + * @since v7.0 + */ ++ (NSSet *)safeMustacheKeys AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end diff --git a/Pods/GRMustache/src/classes/Rendering/GRMustacheTagDelegate.h b/Pods/GRMustache/src/classes/Rendering/GRMustacheTagDelegate.h new file mode 100644 index 0000000..573410f --- /dev/null +++ b/Pods/GRMustache/src/classes/Rendering/GRMustacheTagDelegate.h @@ -0,0 +1,84 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" + +@class GRMustacheTag; + +/** + * Objects conforming to the GRMustacheTagDelegate protocol can observe and + * alter, the rendering of Mustache tags. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/delegate.md + * + * @since v6.0 + */ +@protocol GRMustacheTagDelegate +@optional + +/** + * Sent before a Mustache tag renders. + * + * This method gives an opportunity to alter objects that are rendered. + * + * For example, it is implemented by the NSFormatter class, in templates like + * `{{# dateFormatter }}...{{ value }}...{{ value }}... {{/}}`. + * + * @param tag The Mustache tag about to render. + * @param object The object about to be rendered. + * + * @return The object that should be rendered. + * + * @see GRMustacheTag + * + * @since v6.0 + */ +- (id)mustacheTag:(GRMustacheTag *)tag willRenderObject:(id)object AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Sent after a Mustache tag has rendered. + * + * @param tag The Mustache tag that has just rendered. + * @param object The rendered object. + * @param rendering The actual rendering + * + * @see GRMustacheTag + * + * @since v6.0 + */ +- (void)mustacheTag:(GRMustacheTag *)tag didRenderObject:(id)object as:(NSString *)rendering AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +/** + * Sent right after a Mustache tag has failed rendering. + * + * @param tag The Mustache tag that has just failed rendering. + * @param object The rendered object. + * @param error The error. + * + * @see GRMustacheTag + * + * @since v6.0 + */ +- (void)mustacheTag:(GRMustacheTag *)tag didFailRenderingObject:(id)object withError:(NSError *)error AVAILABLE_GRMUSTACHE_VERSION_7_0_AND_LATER; + +@end diff --git a/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator.m b/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator.m new file mode 100644 index 0000000..6be0ca4 --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator.m @@ -0,0 +1,69 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheExpressionGenerator_private.h" +#import "GRMustacheExpressionVisitor_private.h" +#import "GRMustacheFilteredExpression_private.h" +#import "GRMustacheIdentifierExpression_private.h" +#import "GRMustacheImplicitIteratorExpression_private.h" +#import "GRMustacheScopedExpression_private.h" + + +@interface GRMustacheExpressionGenerator() +@end + +@implementation GRMustacheExpressionGenerator + +- (NSString *)stringWithExpression:(GRMustacheExpression *)expression +{ + [expression acceptVisitor:self error:NULL]; + return _expressionString; +} + + +#pragma mark - + +- (BOOL)visitFilteredExpression:(GRMustacheFilteredExpression *)expression error:(NSError **)error +{ + _expressionString = [NSString stringWithFormat:@"%@(%@)", [self stringWithExpression:expression.filterExpression], [self stringWithExpression:expression.argumentExpression]]; + return YES; +} + +- (BOOL)visitIdentifierExpression:(GRMustacheIdentifierExpression *)expression error:(NSError **)error +{ + _expressionString = expression.identifier; + return YES; +} + +- (BOOL)visitImplicitIteratorExpression:(GRMustacheImplicitIteratorExpression *)expression error:(NSError **)error +{ + _expressionString = @"."; + return YES; +} + +- (BOOL)visitScopedExpression:(GRMustacheScopedExpression *)expression error:(NSError **)error +{ + _expressionString = [NSString stringWithFormat:@"%@.%@", [self stringWithExpression:expression.baseExpression], expression.identifier]; + return YES; +} + +@end diff --git a/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator_private.h b/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator_private.h new file mode 100644 index 0000000..355e378 --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/GRMustacheExpressionGenerator_private.h @@ -0,0 +1,35 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheExpression; + +@interface GRMustacheExpressionGenerator : NSObject { +@private + NSString *_expressionString; +} + +- (NSString *)stringWithExpression:(GRMustacheExpression *)expression GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator.m b/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator.m new file mode 100644 index 0000000..c9b5e2d --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator.m @@ -0,0 +1,163 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheTemplateGenerator_private.h" +#import "GRMustacheExpressionGenerator_private.h" +#import "GRMustacheTemplateASTVisitor_private.h" +#import "GRMustacheTemplateRepository_private.h" +#import "GRMustacheTemplate_private.h" +#import "GRMustacheConfiguration_private.h" +#import "GRMustacheTemplateAST_private.h" +#import "GRMustacheInheritablePartialNode_private.h" +#import "GRMustacheInheritableSectionNode_private.h" +#import "GRMustachePartialNode_private.h" +#import "GRMustacheVariableTag_private.h" +#import "GRMustacheSectionTag_private.h" +#import "GRMustacheTextNode_private.h" + + +@interface GRMustacheTemplateGenerator() +@end + +@implementation GRMustacheTemplateGenerator +@synthesize templateRepository=_templateRepository; + +- (void)dealloc +{ + [_templateRepository release]; + [_expressionGenerator release]; + [super dealloc]; +} + ++ (instancetype)templateGeneratorWithTemplateRepository:(GRMustacheTemplateRepository *)templateRepository +{ + return [[[self alloc] initWithTemplateRepository:templateRepository] autorelease]; +} + +- (NSString *)stringWithTemplate:(GRMustacheTemplate *)template +{ + _templateString = [NSMutableString string]; + [self visitTemplateAST:template.templateAST error:NULL]; + return _templateString; +} + + +#pragma mark - + +- (BOOL)visitTemplateAST:(GRMustacheTemplateAST *)templateAST error:(NSError **)error +{ + for (id ASTNode in templateAST.templateASTNodes) { + [ASTNode acceptTemplateASTVisitor:self error:error]; + } + + return YES; +} + +- (BOOL)visitInheritablePartialNode:(GRMustacheInheritablePartialNode *)inheritablePartialNode error:(NSError **)error +{ + NSString *tagStartDelimiter = _templateRepository.configuration.tagStartDelimiter; + NSString *tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + NSString *partialName = inheritablePartialNode.partialNode.name; + NSString *tagStartString = [NSString stringWithFormat:@"%@<%@%@", tagStartDelimiter, partialName, tagEndDelimiter]; + NSString *tagEndString = [NSString stringWithFormat:@"%@/%@%@", tagStartDelimiter, partialName, tagEndDelimiter]; + + [_templateString appendString:tagStartString]; + [self visitTemplateAST:inheritablePartialNode.overridingTemplateAST error:error]; + [_templateString appendString:tagEndString]; + return YES; +} + +- (BOOL)visitInheritableSectionNode:(GRMustacheInheritableSectionNode *)inheritableSectionNode error:(NSError **)error +{ + NSString *tagStartDelimiter = _templateRepository.configuration.tagStartDelimiter; + NSString *tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + NSString *tagStartString = [NSString stringWithFormat:@"%@$%@%@", tagStartDelimiter, inheritableSectionNode.name, tagEndDelimiter]; + NSString *tagEndString = [NSString stringWithFormat:@"%@/%@%@", tagStartDelimiter, inheritableSectionNode.name, tagEndDelimiter]; + + [_templateString appendString:tagStartString]; + [self visitTemplateAST:inheritableSectionNode.templateAST error:error]; + [_templateString appendString:tagEndString]; + return YES; +} + +- (BOOL)visitPartialNode:(GRMustachePartialNode *)partialNode error:(NSError **)error +{ + NSString *tagStartDelimiter = _templateRepository.configuration.tagStartDelimiter; + NSString *tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + NSString *partialName = partialNode.name; + NSString *tagString = [NSString stringWithFormat:@"%@>%@%@", tagStartDelimiter, partialName, tagEndDelimiter]; + [_templateString appendString:tagString]; + return YES; +} + +- (BOOL)visitVariableTag:(GRMustacheVariableTag *)variableTag error:(NSError **)error +{ + NSString *tagStartDelimiter = nil; + NSString *tagEndDelimiter = nil; + if (variableTag.escapesHTML) { + tagStartDelimiter = _templateRepository.configuration.tagStartDelimiter; + tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + } else { + tagStartDelimiter = [NSString stringWithFormat:@"%@&", _templateRepository.configuration.tagStartDelimiter]; + tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + } + NSString *expressionString = [_expressionGenerator stringWithExpression:variableTag.expression]; + NSString *tagString = [NSString stringWithFormat:@"%@%@%@", tagStartDelimiter, expressionString, tagEndDelimiter]; + [_templateString appendString:tagString]; + return YES; +} + +- (BOOL)visitSectionTag:(GRMustacheSectionTag *)sectionTag error:(NSError **)error +{ + NSString *tagStartDelimiter = _templateRepository.configuration.tagStartDelimiter; + NSString *tagEndDelimiter = _templateRepository.configuration.tagEndDelimiter; + NSString *expressionString = [_expressionGenerator stringWithExpression:sectionTag.expression]; + NSString *sectionPrefix = sectionTag.isInverted ? @"^" : @"#"; + NSString *tagStartString = [NSString stringWithFormat:@"%@%@%@%@", tagStartDelimiter, sectionPrefix, expressionString, tagEndDelimiter]; + NSString *tagEndString = [NSString stringWithFormat:@"%@/%@%@", tagStartDelimiter, expressionString, tagEndDelimiter]; + + [_templateString appendString:tagStartString]; + [self visitTemplateAST:sectionTag.templateAST error:error]; + [_templateString appendString:tagEndString]; + return YES; +} + +- (BOOL)visitTextNode:(GRMustacheTextNode *)textNode error:(NSError **)error +{ + [_templateString appendString:textNode.text]; + return YES; +} + + +#pragma mark - Private + +- (instancetype)initWithTemplateRepository:(GRMustacheTemplateRepository *)templateRepository +{ + self = [super init]; + if (self) { + _templateRepository = [templateRepository retain]; + _expressionGenerator = [[GRMustacheExpressionGenerator alloc] init]; + } + return self; +} + +@end diff --git a/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator_private.h b/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator_private.h new file mode 100644 index 0000000..a9d0b0b --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/GRMustacheTemplateGenerator_private.h @@ -0,0 +1,42 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros_private.h" + +@class GRMustacheTemplate; +@class GRMustacheTemplateRepository; +@class GRMustacheExpressionGenerator; + +@interface GRMustacheTemplateGenerator : NSObject { +@private + GRMustacheTemplateRepository *_templateRepository; + GRMustacheExpressionGenerator *_expressionGenerator; + NSMutableString *_templateString; +} + +@property (nonatomic, retain, readonly) GRMustacheTemplateRepository *templateRepository GRMUSTACHE_API_INTERNAL; + ++ (instancetype)templateGeneratorWithTemplateRepository:(GRMustacheTemplateRepository *)templateRepository GRMUSTACHE_API_INTERNAL; +- (NSString *)stringWithTemplate:(GRMustacheTemplate *)template GRMUSTACHE_API_INTERNAL; + +@end diff --git a/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.h b/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.h new file mode 100644 index 0000000..b3ba1d5 --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.h @@ -0,0 +1,70 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" +#import "GRMustacheRendering.h" +#import "GRMustacheFilter.h" +#import "GRMustacheTagDelegate.h" + +/** + * A category on NSFormatter that allows them to be directly used in GRMustache + * templates. + * + * **Companion guide:** https://github.com/groue/GRMustache/blob/master/Guides/NSFormatter.md + * + * All NSFormatter subclasses such as NSDateFormatter, NSNumberFormatter, and + * your custom subclasses are concerned. + * + * ## Filter facet + * + * A formatter can be used as a filter, as in `{{ percent(value) }}`. Just have + * your `percent` key evaluate to a formatter. + * + * ## Formatting all values in a section + * + * A formatter can be used to format all values in a section of a template: + * + * ``` + * {{# percent }}...{{ value1 }}...{{ value2 }}...{{/ percent }} + * ``` + * + * The formatting then applies to all inner variable tags that evaluate to a + * value that can be processed by the filter (see + * [NSFormatter stringForObjectValue:] documentation). + * + * Inner loops and boolean sections are unaffected. However their inner variable + * tags are: + * + * ``` + * {{# percent }} + *   {{ value1 }}      {{! format applies }} + *   {{# condition }}  {{! format does not apply }} + *     {{ value2 }}    {{! format applies }} + *   {{/ condition }} + * {{/ percent }} + * ``` + * + * @since v6.4 + */ +@interface NSFormatter (GRMustache) +@end diff --git a/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.m b/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.m new file mode 100644 index 0000000..a7e42f7 --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/NSFormatter+GRMustache.m @@ -0,0 +1,108 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "NSFormatter+GRMustache.h" +#import "GRMustacheTag.h" +#import "GRMustacheContext.h" + +@implementation NSFormatter (GRMustache) + +#pragma mark - + +/** + * Support for {{ formatter(value) }} + */ +- (id)transformedValue:(id)object +{ + // [NSNumberFormatter stringForObjectValue:] and + // [NSDateFormatter stringForObjectValue:] return nil or an empty string for + // nil, [NSNull null], and other off-topic values. + // + // Since nil and empty strings do not render anything, and are false when + // controlling boolean sections, we can safely say that formatters do not + // have surprising behavior: just use the plain straight + // stringForObjectValue: without any special care. + return [self stringForObjectValue:object]; +} + +#pragma mark - + +/** + * Support for {{# formatter }}...{{ value }}...{{ value }}...{{/ formatter }} + */ +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ formatter }} + // Behave as a regular object: render self's description + if (HTMLSafe != NULL) { *HTMLSafe = NO; } + return [self description]; + + case GRMustacheTagTypeSection: + // {{# formatter }}...{{/ formatter }} + // {{^ formatter }}...{{/ formatter }} + + // Render normally, but listen to all inner tags rendering, so that + // we can format them. See mustacheTag:willRenderObject: below. + context = [context contextByAddingTagDelegate:self]; + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } +} + +#pragma mark - + +/** + * Support for {{# formatter }}...{{ value }}...{{ value }}...{{/ formatter }} + */ +- (id)mustacheTag:(GRMustacheTag *)tag willRenderObject:(id)object +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: { + // {{ value }} + + NSString *formatted = [self stringForObjectValue:object]; + + if (formatted == nil) { + // NSFormatter documentation for stringForObjectValue: states: + // + // > First test the passed-in object to see if it’s of the correct + // > class. If it isn’t, return nil; but if it is of the right class, + // > return a properly formatted and, if necessary, localized string. + // + // So nil result means that object is not of the correct class. Leave + // it untouched. + + return object; + } + + return formatted; + } + + case GRMustacheTagTypeSection: + // {{# value }} + // {{^ value }} + return object; + } +} + +@end diff --git a/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.h b/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.h new file mode 100644 index 0000000..1e7ff34 --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.h @@ -0,0 +1,34 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheAvailabilityMacros.h" +#import "GRMustacheFilter.h" + +/** + * A category on NSValueTransformer that allows them to be directly used as + * filters in GRMustache templates. + * + * @since v6.4 + */ +@interface NSValueTransformer (GRMustache) +@end diff --git a/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.m b/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.m new file mode 100644 index 0000000..e82afcc --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/NSValueTransformer+GRMustache.m @@ -0,0 +1,26 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "NSValueTransformer+GRMustache.h" + +@implementation NSValueTransformer (GRMustache) +@end diff --git a/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter.m b/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter.m new file mode 100644 index 0000000..3c5d5d7 --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter.m @@ -0,0 +1,186 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheEachFilter_private.h" +#import "GRMustacheRendering_private.h" +#import "GRMustacheContext_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheError.h" + +@implementation GRMustacheEachFilter + +/** + * The transformedValue: method is required by the GRMustacheFilter protocol. + */ + +- (id)transformedValue:(id)object +{ + /** + * Check that parameter can be iterated. + */ + + if (![object respondsToSelector:@selector(countByEnumeratingWithState:objects:count:)]) { + + /** + * Filters have no way to directly return an error. + * + * So let's return a rendering object that will complain when it + * eventually gets rendered. + */ + + return [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) { + if (error) { + *error = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeRenderingError userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"each filter in tag %@ expects its arguments to conform to the NSFastEnumeration protocol. %@ is not.", tag, object] }]; + } + return nil; + }]; + } + + + /** + * Index-based collections and key-based collections are not iterated in the + * same way. + */ + + if ([object isKindOfClass:[NSDictionary class]]) { + return [self transformedDictionary:object]; + } else { + return [self transformedArray:object]; + } +} + +- (id)transformedArray:(id)array +{ + /** + * Let's return an array containing as many objects as in the original + * collection. + * + * Returning an array is important: it allows the `each` filter to be + * chained with other collection-processing filters, as in + * {{# reverse(each(list)) }}...{{/}} for example. + * + * The new array contains objects that perform custom rendering by enqueuing + * in the context stack the positional keys before rendering just like the + * original objects. + * + * Those objects which perform custom rendering conform to the + * GRMustacheRendering protocol: + */ + + NSMutableArray *replacementRenderingObjects = [NSMutableArray array]; + __block NSUInteger indexOfLastObject = 0; + NSUInteger index = 0; + for (id object in array) { + + /** + * Build the replacement rendering object. + * + * It enqueues the positional keys, and then renders the same as the + * original object. + */ + + indexOfLastObject = index; + id replacementRenderingObject = [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) { + + /** + * Add our positional keys in the rendering context + */ + + context = [context contextByAddingObject:@{@"@index": @(index), + @"@indexPlusOne": @(index + 1), + @"@indexIsEven": @(index % 2 == 0), + @"@first": @(index == 0), + @"@last": @(index == indexOfLastObject), // When this is evaluated, on rendering, the filter will have been long executed. The __block variable indexOfLastObject will have the value of the last index. + }]; + + /** + * We want to render just like the original object. + */ + + id originalRenderingObject = [GRMustacheRendering renderingObjectForObject:object]; + return [originalRenderingObject renderForMustacheTag:tag asEnumerationItem:YES context:context HTMLSafe:HTMLSafe error:error]; + }]; + + [replacementRenderingObjects addObject:replacementRenderingObject]; + ++index; + } + + return replacementRenderingObjects; +} + +- (id)transformedDictionary:(NSDictionary *)dictionary +{ + /** + * Let's return an array containing as many objects as in the original + * dictionary. + * + * The new array contains objects that perform custom rendering by enqueuing + * in the context stack the positional keys before rendering just like the + * original dictionary values. + * + * Those objects which perform custom rendering conform to the + * GRMustacheRendering protocol: + */ + + NSMutableArray *replacementRenderingObjects = [NSMutableArray array]; + NSUInteger indexOfLastObject = dictionary.count - 1; + NSUInteger index = 0; + for (id key in dictionary) { + + /** + * Build the replacement rendering object. + * + * It enqueues the positional keys, and then renders the same as the + * original object. + */ + + id object = [dictionary objectForKey:key]; + id replacementRenderingObject = [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) { + + /** + * Add our positional keys in the rendering context + */ + + context = [context contextByAddingObject:@{@"@key": key, + @"@index": @(index), + @"@indexPlusOne": @(index + 1), + @"@indexIsEven": @(index % 2 == 0), + @"@first": @(index == 0), + @"@last": @(index == indexOfLastObject), + }]; + + /** + * We want to render just like the original object. + */ + + id originalRenderingObject = [GRMustacheRendering renderingObjectForObject:object]; + return [originalRenderingObject renderForMustacheTag:tag asEnumerationItem:YES context:context HTMLSafe:HTMLSafe error:error]; + }]; + + [replacementRenderingObjects addObject:replacementRenderingObject]; + ++index; + } + + return replacementRenderingObjects; +} + +@end diff --git a/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter_private.h b/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter_private.h new file mode 100644 index 0000000..a0261a0 --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheEachFilter_private.h @@ -0,0 +1,27 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheFilter_private.h" + +@interface GRMustacheEachFilter : NSObject + +@end diff --git a/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary.m b/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary.m new file mode 100644 index 0000000..cce13c1 --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary.m @@ -0,0 +1,107 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheHTMLLibrary_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheContext_private.h" +#import "GRMustacheTranslateCharacters_private.h" + +// ============================================================================= +#pragma mark - GRMustacheHTMLEscapeFilter + +@implementation GRMustacheHTMLEscapeFilter + +#pragma mark + +/** + * Support for {{ HTML.escape(value) }} + */ +- (id)transformedValue:(id)object +{ + // Specific case for [NSNull null] + + if (object == [NSNull null]) { + return @""; + } + + // Turns other objects into strings, and escape + + NSString *string = [object description]; + return GRMustacheTranslateHTMLCharacters(string); +} + + +#pragma mark - + +/** + * Support for {{# HTML.escape }}...{{ value }}...{{ value }}...{{/ HTML.escape }} + */ +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ HTML.escape }} + // Behave as a regular object: render self's description + if (HTMLSafe != NULL) { *HTMLSafe = NO; } + return [self description]; + + case GRMustacheTagTypeSection: + // {{# HTML.escape }}...{{/ HTML.escape }} + // {{^ HTML.escape }}...{{/ HTML.escape }} + + // Render normally, but listen to all inner tags rendering, so that + // we can format them. See mustacheTag:willRenderObject: below. + context = [context contextByAddingTagDelegate:self]; + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } +} + + +#pragma mark - + +/** + * Support for {{# HTML.escape }}...{{ value }}...{{ value }}...{{/ HTML.escape }} + */ +- (id)mustacheTag:(GRMustacheTag *)tag willRenderObject:(id)object +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ value }} + // + // We can not escape `object`, because it is not a string. + // We want to escape its rendering. + // So return a rendering object that will eventually render `object`, + // and escape its rendering. + return [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) { + id renderingObject = [GRMustacheRendering renderingObjectForObject:object]; + NSString *rendering = [renderingObject renderForMustacheTag:tag context:context HTMLSafe:HTMLSafe error:error]; + return GRMustacheTranslateHTMLCharacters(rendering); + }]; + + case GRMustacheTagTypeSection: + // {{# value }} + // {{^ value }} + return object; + } +} + +@end diff --git a/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary_private.h b/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary_private.h new file mode 100644 index 0000000..2a973ff --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheHTMLLibrary_private.h @@ -0,0 +1,33 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "GRMustacheRendering_private.h" +#import "GRMustacheFilter_private.h" +#import "GRMustacheTagDelegate.h" + + +// ============================================================================= +#pragma mark - GRMustacheHTMLEscapeFilter + +@interface GRMustacheHTMLEscapeFilter: NSObject +@end diff --git a/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheJavascriptLibrary.m b/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheJavascriptLibrary.m new file mode 100644 index 0000000..0bf3ccc --- /dev/null +++ b/Pods/GRMustache/src/classes/Services/StandardLibrary/GRMustacheJavascriptLibrary.m @@ -0,0 +1,239 @@ +// The MIT License +// +// Copyright (c) 2014 Gwendal Roué +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "GRMustacheJavascriptLibrary_private.h" +#import "GRMustacheTag_private.h" +#import "GRMustacheContext_private.h" + + +// ============================================================================= +#pragma mark - GRMustacheJavascriptEscaper + +@implementation GRMustacheJavascriptEscaper + +#pragma mark + +/** + * Support for {{ javascript.escape(value) }} + */ +- (id)transformedValue:(id)object +{ + // Specific case for [NSNull null] + + if (object == [NSNull null]) { + return @""; + } + + // Turns other objects into strings, and escape + + NSString *string = [object description]; + return [self escape:string]; +} + + +#pragma mark - + +/** + * Support for {{# javascript.escape }}...{{ value }}...{{ value }}...{{/ javascript.escape }} + */ +- (NSString *)renderForMustacheTag:(GRMustacheTag *)tag context:(GRMustacheContext *)context HTMLSafe:(BOOL *)HTMLSafe error:(NSError **)error +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ javascript.escape }} + // Behave as a regular object: render self's description + if (HTMLSafe != NULL) { *HTMLSafe = NO; } + return [self description]; + + case GRMustacheTagTypeSection: + // {{# javascript.escape }}...{{/ javascript.escape }} + // {{^ javascript.escape }}...{{/ javascript.escape }} + + // Render normally, but listen to all inner tags rendering, so that + // we can format them. See mustacheTag:willRenderObject: below. + context = [context contextByAddingTagDelegate:self]; + return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error]; + } +} + + +#pragma mark - + +/** + * Support for {{# javascript.escape }}...{{ value }}...{{ value }}...{{/ javascript.escape }} + */ +- (id)mustacheTag:(GRMustacheTag *)tag willRenderObject:(id)object +{ + switch (tag.type) { + case GRMustacheTagTypeVariable: + // {{ value }} + // + // We can not escape `object`, because it is not a string. + // We want to escape its rendering. + // So return a rendering object that will eventually render `object`, + // and escape its rendering. + return [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) { + id renderingObject = [GRMustacheRendering renderingObjectForObject:object]; + NSString *rendering = [renderingObject renderForMustacheTag:tag context:context HTMLSafe:HTMLSafe error:error]; + return [self escape:rendering]; + }]; + + case GRMustacheTagTypeSection: + // {{# value }} + // {{^ value }} + return object; + } +} + + +#pragma mark - Private + +- (NSString *)escape:(NSString *)string +{ + NSUInteger length = [string length]; + if (length == 0) { + return string; + } + + + // Extract characters + + const UniChar *characters = CFStringGetCharactersPtr((CFStringRef)string); + if (!characters) { + NSMutableData *data = [NSMutableData dataWithLength:length * sizeof(UniChar)]; + [string getCharacters:[data mutableBytes] range:(NSRange){ .location = 0, .length = length }]; + characters = [data bytes]; + } + + + // Set up the translation table + + static const NSString *escapeForCharacter[] = { + // This table comes from https://github.com/django/django/commit/8c4a525871df19163d5bfdf5939eff33b544c2e2#django/template/defaultfilters.py + // + // Quoting Malcolm Tredinnick: + // > Added extra robustness to the escapejs filter so that all invalid + // > characters are correctly escaped. This avoids any chance to inject + // > raw HTML inside