├── ObjCnalization ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── Translation(s) │ ├── LoadedTranslationTypeObject.m │ ├── TranslationsLoader.h │ ├── LoadedTranslation.m │ ├── LoadedTranslationTypeObject.h │ ├── LoadedTranslation.h │ ├── LoadedTranslationsProcessor.h │ ├── TranslationsLoader.m │ └── LoadedTranslationsProcessor.m │ ├── Parsers │ ├── InequalityExtendedExpressionParser.h │ ├── RegexExpressionParser.h │ ├── InequalityExpressionParser.h │ ├── RegexExpressionParser.m │ ├── InequalityExpressionParser.m │ └── InequalityExtendedExpressionParser.m │ ├── Expression(s) │ ├── SharedExpressionsLoader.h │ ├── SharedExpression-(Localization) │ │ ├── SharedBaseExpression.h │ │ ├── SharedRussianExpression.h │ │ ├── SharedPolishExpression.h │ │ ├── SharedBaseExpression.m │ │ ├── SharedPolishExpression.m │ │ └── SharedRussianExpression.m │ ├── SharedExpression.m │ ├── SharedExpression.h │ ├── SharedExpressionsLoader.m │ ├── SharedExpressionsProcessor.h │ ├── Expression.h │ ├── Expression.m │ └── SharedExpressionsProcessor.m │ ├── LengthVariation.m │ ├── Protocol(s) │ ├── ExpressionParser.h │ └── ExpressionMatcher.h │ ├── Matcher(s) │ ├── RegexExpressionMatcher.h │ ├── RegexExpressionMatcher.m │ ├── InequalityExpressionMatcher.h │ ├── InequalityExtendedExpressionMatcher.h │ ├── InequalityExtendedExpressionMatcher.m │ └── InequalityExpressionMatcher.m │ ├── Enum(s) │ ├── InternalPatternObject.h │ ├── ExpressionPatternTypeObject.h │ ├── InternalPatternObject.m │ ├── InequalitySignObject.h │ ├── ExpressionPatternTypeObject.m │ └── InequalitySignObject.m │ ├── Translation.h │ ├── LengthVariation.h │ ├── Categories │ ├── NSArray+HighOrder │ │ ├── NSArray+HighOrder.h │ │ └── NSArray+HighOrder.m │ ├── NSDictionary+Collection │ │ ├── NSDictionary+Collection.h │ │ └── NSDictionary+Collection.m │ ├── RVCollection.h │ ├── NSString+Collection │ │ ├── NSString+Collection.h │ │ └── NSString+Collection.m │ └── NSArray+Collection │ │ ├── NSArray+Collection.h │ │ └── NSArray+Collection.m │ ├── Loader(s) │ ├── JSONFileLoader.h │ └── JSONFileLoader.m │ ├── Regex.h │ ├── Translation.m │ ├── Regex.m │ ├── ObjCnalization.m │ └── ObjCnalization.h ├── _Pods.xcodeproj ├── Example ├── ObjCnalization │ ├── pl.lproj │ │ ├── LaunchScreen.strings │ │ └── InfoPlist.strings │ ├── ru.lproj │ │ ├── LaunchScreen.strings │ │ └── InfoPlist.strings │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── RXViewController.h │ ├── RXAppDelegate.h │ ├── main.m │ ├── ObjCnalization-Prefix.pch │ ├── localizations │ │ ├── expressions.json │ │ ├── en.json │ │ ├── base.json │ │ ├── pl.json │ │ └── ru.json │ ├── RXViewController.m │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── ObjCnalization-Info.plist │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ └── RXAppDelegate.m ├── Tests │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── pl.lproj │ │ └── InfoPlist.strings │ ├── ru.lproj │ │ └── InfoPlist.strings │ ├── Tests-Prefix.pch │ ├── Tests.m │ └── Tests-Info.plist ├── Pods │ ├── Target Support Files │ │ ├── ObjCnalization │ │ │ ├── ObjCnalization.modulemap │ │ │ ├── ObjCnalization-dummy.m │ │ │ ├── ObjCnalization-prefix.pch │ │ │ ├── ObjCnalization.xcconfig │ │ │ ├── Info.plist │ │ │ └── ObjCnalization-umbrella.h │ │ ├── Pods-ObjCnalization_Tests │ │ │ ├── Pods-ObjCnalization_Tests-acknowledgements.markdown │ │ │ ├── Pods-ObjCnalization_Tests.modulemap │ │ │ ├── Pods-ObjCnalization_Tests-dummy.m │ │ │ ├── Pods-ObjCnalization_Tests-umbrella.h │ │ │ ├── Pods-ObjCnalization_Tests.debug.xcconfig │ │ │ ├── Pods-ObjCnalization_Tests.release.xcconfig │ │ │ ├── Info.plist │ │ │ ├── Pods-ObjCnalization_Tests-acknowledgements.plist │ │ │ ├── Pods-ObjCnalization_Tests-frameworks.sh │ │ │ └── Pods-ObjCnalization_Tests-resources.sh │ │ └── Pods-ObjCnalization_Example │ │ │ ├── Pods-ObjCnalization_Example.modulemap │ │ │ ├── Pods-ObjCnalization_Example-dummy.m │ │ │ ├── Pods-ObjCnalization_Example-umbrella.h │ │ │ ├── Pods-ObjCnalization_Example.debug.xcconfig │ │ │ ├── Pods-ObjCnalization_Example.release.xcconfig │ │ │ ├── Info.plist │ │ │ ├── Pods-ObjCnalization_Example-acknowledgements.markdown │ │ │ ├── Pods-ObjCnalization_Example-acknowledgements.plist │ │ │ ├── Pods-ObjCnalization_Example-frameworks.sh │ │ │ └── Pods-ObjCnalization_Example-resources.sh │ ├── Manifest.lock │ └── Local Podspecs │ │ └── ObjCnalization.podspec.json ├── Podfile ├── ObjCnalization.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── ObjCnalization-Example.xcscheme ├── ObjCnalization.xcworkspace │ └── contents.xcworkspacedata └── Podfile.lock ├── logo.png ├── jokeAboutSwift.png ├── addLocalizationInXcodeSettings.png ├── .travis.yml ├── .gitignore ├── LICENSE └── ObjCnalization.podspec /ObjCnalization/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj -------------------------------------------------------------------------------- /Example/ObjCnalization/pl.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Example/ObjCnalization/ru.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m1a7/ObjCnalization/HEAD/logo.png -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/Tests/pl.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/Tests/ru.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /jokeAboutSwift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m1a7/ObjCnalization/HEAD/jokeAboutSwift.png -------------------------------------------------------------------------------- /Example/ObjCnalization/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/ObjCnalization/pl.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/ObjCnalization/ru.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /addLocalizationInXcodeSettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m1a7/ObjCnalization/HEAD/addLocalizationInXcodeSettings.png -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ObjCnalization/ObjCnalization.modulemap: -------------------------------------------------------------------------------- 1 | framework module ObjCnalization { 2 | umbrella header "ObjCnalization-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ObjCnalization/ObjCnalization-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_ObjCnalization : NSObject 3 | @end 4 | @implementation PodsDummy_ObjCnalization 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'ObjCnalization_Example' do 4 | pod 'ObjCnalization', :path => '../' 5 | 6 | target 'ObjCnalization_Tests' do 7 | inherit! :search_paths 8 | 9 | 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Tests/Pods-ObjCnalization_Tests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Tests/Pods-ObjCnalization_Tests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_ObjCnalization_Tests { 2 | umbrella header "Pods-ObjCnalization_Tests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/ObjCnalization.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Example/Pods-ObjCnalization_Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_ObjCnalization_Example { 2 | umbrella header "Pods-ObjCnalization_Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Tests/Pods-ObjCnalization_Tests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_ObjCnalization_Tests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_ObjCnalization_Tests 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Example/Pods-ObjCnalization_Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_ObjCnalization_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_ObjCnalization_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/ObjCnalization/RXViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RXViewController.h 3 | // ObjCnalization 4 | // 5 | // Created by m1a7 on 12/04/2017. 6 | // Copyright (c) 2017 m1a7. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface RXViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ObjCnalization/ObjCnalization-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/ObjCnalization.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Translation(s)/LoadedTranslationTypeObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // LoadedTranslationTypeObject.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "LoadedTranslationTypeObject.h" 10 | 11 | @implementation LoadedTranslationTypeObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/ObjCnalization/RXAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // RXAppDelegate.h 3 | // ObjCnalization 4 | // 5 | // Created by m1a7 on 12/04/2017. 6 | // Copyright (c) 2017 m1a7. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface RXAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ObjCnalization (0.1.0) 3 | 4 | DEPENDENCIES: 5 | - ObjCnalization (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | ObjCnalization: 9 | :path: ../ 10 | 11 | SPEC CHECKSUMS: 12 | ObjCnalization: 5b7f0704499b529e891d3a1caf76455976bcc21e 13 | 14 | PODFILE CHECKSUM: 840862d6c0ac46dcf1b3338934f59b8f3d400f3e 15 | 16 | COCOAPODS: 1.3.0.beta.3 17 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ObjCnalization (0.1.0) 3 | 4 | DEPENDENCIES: 5 | - ObjCnalization (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | ObjCnalization: 9 | :path: ../ 10 | 11 | SPEC CHECKSUMS: 12 | ObjCnalization: 5b7f0704499b529e891d3a1caf76455976bcc21e 13 | 14 | PODFILE CHECKSUM: 840862d6c0ac46dcf1b3338934f59b8f3d400f3e 15 | 16 | COCOAPODS: 1.3.0.beta.3 17 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Parsers/InequalityExtendedExpressionParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // InequalityExtendedExpressionParser.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "InequalityExpressionParser.h" 10 | 11 | @interface InequalityExtendedExpressionParser : InequalityExpressionParser 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/ObjCnalization/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ObjCnalization 4 | // 5 | // Created by m1a7 on 12/04/2017. 6 | // Copyright (c) 2017 m1a7. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "RXAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([RXAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/ObjCnalization/ObjCnalization-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpressionsLoader.h: -------------------------------------------------------------------------------- 1 | // 2 | // SharedExpressionsLoader.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SharedExpression.h" 11 | 12 | @interface SharedExpressionsLoader : NSObject 13 | 14 | + (NSArray*)loadExpressions:(NSDictionary*) json; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpression-(Localization)/SharedBaseExpression.h: -------------------------------------------------------------------------------- 1 | // 2 | // SharedBaseExpression.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SharedExpression.h" 11 | 12 | @interface SharedBaseExpression : NSObject 13 | 14 | +(NSArray*) allExpressions; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpression-(Localization)/SharedRussianExpression.h: -------------------------------------------------------------------------------- 1 | // 2 | // SharedRussianExpression.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SharedExpression.h" 11 | @interface SharedRussianExpression : NSObject 12 | 13 | +(NSArray*) allExpressions; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpression-(Localization)/SharedPolishExpression.h: -------------------------------------------------------------------------------- 1 | // 2 | // SharedPolishExpression.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SharedExpression.h" 11 | 12 | @interface SharedPolishExpression : NSObject 13 | 14 | +(NSArray*) allExpressions; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Tests/Pods-ObjCnalization_Tests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ObjCnalization_TestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ObjCnalization_TestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Example/Pods-ObjCnalization_Example-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ObjCnalization_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ObjCnalization_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/ObjCnalization/localizations/expressions.json: -------------------------------------------------------------------------------- 1 | { 2 | "base": { 3 | "ten": "ie:x=10", 4 | ">20": "ie:x>20", 5 | "custom-pl-few": "exp:(.*(?=1).[0-9]$)|(^[05-9]$)|(.*(?!1).[0156789])" 6 | }, 7 | 8 | "pl": { 9 | "few": "exp:(((?!1).[2-4]{1})$)|(^[2-4]$)", 10 | "two": "ie:x=2", 11 | "three": "ie:x=3" 12 | }, 13 | 14 | "ru": { 15 | "few": "exp:(((?!1).[2-4]{1})$)|(^[2-4]$)", 16 | "two": "ie:x=2", 17 | "three": "ie:x=3", 18 | } 19 | } -------------------------------------------------------------------------------- /ObjCnalization/Classes/LengthVariation.m: -------------------------------------------------------------------------------- 1 | // 2 | // LengthVariation.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 20/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "LengthVariation.h" 10 | 11 | @implementation LengthVariation 12 | 13 | - (instancetype)initWithWidth:(NSInteger) width strValue:(NSString*) value 14 | { 15 | self = [super init]; 16 | if (self) { 17 | self.width = width; 18 | self.value = value; 19 | } 20 | return self; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpression.m: -------------------------------------------------------------------------------- 1 | // 2 | // SharedExpression.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "SharedExpression.h" 10 | 11 | @implementation SharedExpression 12 | 13 | - (instancetype)init:(NSString*)identifier andPattern:(NSString*) pattern 14 | { 15 | self = [super init]; 16 | if (self) { 17 | self.identifier = identifier; 18 | self.pattern = pattern; 19 | } 20 | return self; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Protocol(s)/ExpressionParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExpressionParser.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ExpressionMatcher.h" 11 | 12 | typedef NSString ExpressionPattern; 13 | 14 | 15 | @protocol ExpressionParser 16 | 17 | @property (nonatomic, strong) ExpressionPattern* pattern; 18 | 19 | - (id) parse; 20 | - (instancetype)initWithPattern:(NSString*) pattern; 21 | 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ObjCnalization/ObjCnalization.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/ObjCnalization 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | PODS_BUILD_DIR = $BUILD_DIR 5 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Matcher(s)/RegexExpressionMatcher.h: -------------------------------------------------------------------------------- 1 | // 2 | // RegexExpressionMatcher.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ExpressionMatcher.h" 11 | 12 | typedef NSString RegexPattern; 13 | 14 | @interface RegexExpressionMatcher : NSObject 15 | 16 | @property (nonatomic, strong) RegexPattern* pattern; 17 | 18 | - (instancetype)initWithPattern:(RegexPattern*) pattern; 19 | - (BOOL) validate:(NSString*) val; 20 | 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode7.3 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/ObjCnalization.xcworkspace -scheme ObjCnalization-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint 15 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Enum(s)/InternalPatternObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // InternalPattern.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef enum { 12 | InternalPatternEnum_Expression, 13 | InternalPatternEnum_ExpressionPatternType, 14 | InternalPatternEnum_KeyWithoutExpression 15 | 16 | } InternalPatternEnum; 17 | 18 | 19 | @interface InternalPatternObject : NSObject 20 | 21 | +(NSString*) getStringFromInternalPatternEnum:(InternalPatternEnum) enumType; 22 | 23 | @end 24 | 25 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Tests/Pods-ObjCnalization_Tests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ObjCnalization" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/ObjCnalization/ObjCnalization.framework/Headers" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Tests/Pods-ObjCnalization_Tests.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ObjCnalization" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/ObjCnalization/ObjCnalization.framework/Headers" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Translation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Translation.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class Expression; 12 | 13 | 14 | @interface Translation : NSObject 15 | 16 | @property (nonatomic, strong) NSString* key; 17 | @property (nonatomic, strong) NSArray* expressions; 18 | 19 | - (NSString*) validate:(NSString*) text andFittingWidth:(NSInteger) fittingWidth; 20 | 21 | - (instancetype)initWithKey:(NSString*) key andExpressions:(NSArray*) expressions; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpression.h: -------------------------------------------------------------------------------- 1 | // 2 | // SharedExpression.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface SharedExpression : NSObject 13 | 14 | @property (nonatomic, strong) NSString* identifier; 15 | @property (nonatomic, strong) NSString* pattern; 16 | 17 | - (instancetype)init:(NSString*)identifier andPattern:(NSString*) pattern; 18 | 19 | @end 20 | 21 | 22 | @protocol SharedExpressionProtocol 23 | 24 | + (NSArray*)allExpressions; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/LengthVariation.h: -------------------------------------------------------------------------------- 1 | // 2 | // LengthVariation.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 20/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LengthVariation : NSObject 12 | 13 | /** 14 | Max width of a screen on which the `value` should be presented. 15 | */ 16 | @property (assign, nonatomic) NSInteger width; 17 | 18 | /** 19 | String with localized content in some language. 20 | */ 21 | @property (strong, nonatomic) NSString* value; 22 | 23 | - (instancetype)initWithWidth:(NSInteger) width strValue:(NSString*) value; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Translation(s)/TranslationsLoader.h: -------------------------------------------------------------------------------- 1 | // 2 | // TranslationsLoader.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "LoadedTranslation.h" 11 | 12 | typedef NSDictionary JSONDictionary; 13 | 14 | @interface TranslationsLoader : NSObject 15 | 16 | #pragma mark - Public methods 17 | + (NSArray*) loadTranslations:(NSDictionary*) json; 18 | 19 | #pragma mark - Private methods 20 | + (LoadedTranslationTypeEnum) detectElementType:(JSONDictionary*) element; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Matcher(s)/RegexExpressionMatcher.m: -------------------------------------------------------------------------------- 1 | // 2 | // RegexExpressionMatcher.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "RegexExpressionMatcher.h" 10 | #import "Regex.h" 11 | 12 | @implementation RegexExpressionMatcher 13 | 14 | - (instancetype)initWithPattern:(RegexPattern*) pattern 15 | { 16 | self = [super init]; 17 | if (self) { 18 | self.pattern = pattern; 19 | } 20 | return self; 21 | } 22 | 23 | - (BOOL) validate:(NSString*) val 24 | { 25 | return [Regex firstMatchInString:val andPattern:self.pattern] != nil; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Translation(s)/LoadedTranslation.m: -------------------------------------------------------------------------------- 1 | // 2 | // LoadedTranslation.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "LoadedTranslation.h" 10 | 11 | @implementation LoadedTranslation 12 | 13 | - (instancetype)initWithType:(LoadedTranslationTypeEnum) type andKey:(NSString*) key andContent:(NSDictionary*) content; 14 | { 15 | self = [super init]; 16 | if (self) { 17 | self.typeEnum = type; 18 | self.keyForDict = key; 19 | self.content = [NSDictionary dictionaryWithDictionary:content]; 20 | } 21 | return self; 22 | } 23 | @end 24 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Matcher(s)/InequalityExpressionMatcher.h: -------------------------------------------------------------------------------- 1 | // 2 | // InequalityExpressionMatcher.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ExpressionMatcher.h" 11 | #import "InequalitySignObject.h" 12 | 13 | @interface InequalityExpressionMatcher : NSObject 14 | 15 | @property (nonatomic, assign) InequalitySignEnum sign; 16 | @property (nonatomic, assign) double value; 17 | 18 | - (instancetype)initWithInequalitySignEnum:(InequalitySignEnum) enumValue withValue:(double) value; 19 | - (BOOL) validate:(NSString *)val; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Translation(s)/LoadedTranslationTypeObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // LoadedTranslationTypeObject.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef enum { 12 | LoadedTranslationTypeEnum_Simple = 0, 13 | LoadedTranslationTypeEnum_WithExpressions, 14 | LoadedTranslationTypeEnum_WithLengthVariations, 15 | LoadedTranslationTypeEnum_WithExpressionsAndLengthVariations, 16 | 17 | LoadedTranslationTypeEnum_ErrorInitialization 18 | 19 | } LoadedTranslationTypeEnum; 20 | 21 | 22 | @interface LoadedTranslationTypeObject : NSObject 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Example/Pods-ObjCnalization_Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ObjCnalization" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/ObjCnalization/ObjCnalization.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "ObjCnalization" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Example/Pods-ObjCnalization_Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ObjCnalization" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/ObjCnalization/ObjCnalization.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "ObjCnalization" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Categories/NSArray+HighOrder/NSArray+HighOrder.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+HighOrder.h 3 | // Collection 4 | // 5 | // Created by Badchoice on 10/10/17. 6 | // Copyright © 2017 Revo. All rights reserved. 7 | // 8 | 9 | #import "NSArray+Collection.h" 10 | 11 | @interface NSArray (HighOrder) 12 | 13 | -(NSArray*)map_:(SEL)selector; 14 | -(NSArray*)map_:(SEL)selector withObject:(id)object; 15 | 16 | -(void)each_:(SEL)selector; 17 | -(void)each_:(SEL)selector withObject:(id)object; 18 | 19 | -(NSArray*)filter_:(SEL)selector; 20 | -(NSArray*)filter_:(SEL)selector withObject:(id)object; 21 | 22 | -(NSArray*)reject_:(SEL)selector; 23 | -(NSArray*)reject_:(SEL)selector withObject:(id)object; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Translation(s)/LoadedTranslation.h: -------------------------------------------------------------------------------- 1 | // 2 | // LoadedTranslation.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "LoadedTranslationTypeObject.h" 11 | 12 | @interface LoadedTranslation : NSObject 13 | 14 | @property (nonatomic, assign) LoadedTranslationTypeEnum typeEnum; 15 | 16 | @property (nonatomic, strong) NSString* keyForDict; 17 | 18 | @property (nonatomic, strong) NSDictionary* content; 19 | 20 | - (instancetype)initWithType:(LoadedTranslationTypeEnum) type andKey:(NSString*) key andContent:(NSDictionary*) content; 21 | 22 | @end 23 | 24 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Parsers/RegexExpressionParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // RegexExpressionParser.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ExpressionParser.h" 11 | #import "ExpressionMatcher.h" 12 | #import "RegexExpressionMatcher.h" 13 | #import "Regex.h" 14 | #import "ExpressionPatternTypeObject.h" 15 | 16 | typedef NSString ExpressionPattern; 17 | 18 | @interface RegexExpressionParser : NSObject 19 | 20 | 21 | @property (nonatomic, strong) ExpressionPattern* pattern; 22 | 23 | - (instancetype)initWithPattern:(NSString *)pattern; 24 | - (id ) parse; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Loader(s)/JSONFileLoader.h: -------------------------------------------------------------------------------- 1 | // 2 | // JSONFileLoader.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NSDictionary JSONDictionary; 12 | typedef NSString CountryCode; 13 | 14 | @interface JSONFileLoader : NSObject 15 | 16 | + (JSONDictionary*) loadTranslations:(CountryCode*) countryCode andBundle:(NSBundle*) bundle; 17 | + (NSDictionary*) loadExpressions:(CountryCode*) countryCode andBundle:(NSBundle*) bundle; 18 | 19 | + (JSONDictionary*) load:(NSString*) fileName andBundle:(NSBundle*) bundle; 20 | + (JSONDictionary*) load:(NSURL*) fileURL; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Regex.h: -------------------------------------------------------------------------------- 1 | // 2 | // Regex.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Regex : NSObject 12 | 13 | + (NSString*) matchInString:(NSString*) str andPattern:(NSString*) pattern andCapturingGroupIdx:(NSInteger)capturingGroupIdx; 14 | + (NSString*) firstMatchInString:(NSString*) str andPattern:(NSString*) pattern; 15 | + (NSArray*) matchesInString:(NSString*) str andPattern:(NSString*) pattern; 16 | 17 | #pragma mark - Private methods 18 | + (NSRegularExpression*) regexp:(NSString*) pattern; 19 | + (NSString*) substring:(NSString*)str andRange:(NSRange) range; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Protocol(s)/ExpressionMatcher.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExpressionMatcher.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 20/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | Protocol that is the base protocol to conform for expression matchers like 13 | `InequalityExpressionMatcher` or `RegexExpressionMatcher`. 14 | */ 15 | 16 | @protocol ExpressionMatcher 17 | 18 | /** 19 | Method used to validate passed `val` parameter. 20 | 21 | :param: val string value that will be used to match expression. 22 | :returns: `true` if value matches expression, otherwise `false`. 23 | */ 24 | 25 | - (BOOL) validate:(NSString*) val; 26 | 27 | @end 28 | 29 | 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | Carthage 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 29 | # 30 | # Note: if you ignore the Pods directory, make sure to uncomment 31 | # `pod install` in .travis.yml 32 | # 33 | # Pods/ 34 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/ObjCnalization.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ObjCnalization", 3 | "version": "0.1.0", 4 | "summary": "Localize iOS apps in a smarter way using JSON files. ObjC framework.", 5 | "description": "ObjC library that helps in localizing apps in a different, better, simpler, more powerful way than system localization does", 6 | "homepage": "https://github.com/m1a7/ObjCnalization", 7 | "license": { 8 | "type": "MIT", 9 | "file": "LICENSE" 10 | }, 11 | "authors": { 12 | "m1a7": "thisismymail03@gmail.com" 13 | }, 14 | "source": { 15 | "git": "https://github.com/m1a7/ObjCnalization.git", 16 | "tag": "0.1.0" 17 | }, 18 | "platforms": { 19 | "ios": "8.0" 20 | }, 21 | "source_files": "ObjCnalization/Classes/**/*" 22 | } 23 | -------------------------------------------------------------------------------- /Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjCnalizationTests.m 3 | // ObjCnalizationTests 4 | // 5 | // Created by m1a7 on 12/04/2017. 6 | // Copyright (c) 2017 m1a7. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | 11 | @interface Tests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Tests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Matcher(s)/InequalityExtendedExpressionMatcher.h: -------------------------------------------------------------------------------- 1 | // 2 | // InequalityExtendedExpressionMatcher.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ExpressionMatcher.h" 11 | #import "InequalityExpressionMatcher.h" 12 | 13 | @interface InequalityExtendedExpressionMatcher : NSObject 14 | 15 | 16 | @property (nonatomic, strong) InequalityExpressionMatcher* leftMatcher; 17 | @property (nonatomic, strong) InequalityExpressionMatcher* rightMatcher; 18 | 19 | - (instancetype)initWithLeftMatcher:(InequalityExpressionMatcher*) left rightMatcher:(InequalityExpressionMatcher*) right; 20 | - (BOOL) validate:(NSString *)val; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Matcher(s)/InequalityExtendedExpressionMatcher.m: -------------------------------------------------------------------------------- 1 | // 2 | // InequalityExtendedExpressionMatcher.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "InequalityExtendedExpressionMatcher.h" 10 | 11 | @implementation InequalityExtendedExpressionMatcher 12 | 13 | - (instancetype)initWithLeftMatcher:(InequalityExpressionMatcher*) left rightMatcher:(InequalityExpressionMatcher*) right 14 | { 15 | self = [super init]; 16 | if (self) { 17 | self.leftMatcher = left; 18 | self.rightMatcher = right; 19 | } 20 | return self; 21 | } 22 | 23 | - (BOOL) validate:(NSString *)val 24 | { 25 | return [self.leftMatcher validate:val] && [self.rightMatcher validate:val]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Translation(s)/LoadedTranslationsProcessor.h: -------------------------------------------------------------------------------- 1 | // 2 | // LoadedTranslationsProcessor.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | @class Translation; 11 | @class LoadedTranslation; 12 | @class SharedExpression; 13 | 14 | @interface LoadedTranslationsProcessor : NSObject 15 | 16 | + (NSArray*) processTranslations:(NSArray*) baseTranslations 17 | andPreferedLanguageTranslations:(NSArray*) preferedLanguageTranslations 18 | andSharedExpressions:(NSArray*) sharedExpressions; 19 | 20 | + (NSInteger) parseNumberFromLengthVariation:(NSString*) string; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Categories/NSDictionary+Collection/NSDictionary+Collection.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+Collection.h 3 | // Collection 4 | // 5 | // Created by Jordi Puigdellívol on 10/8/16. 6 | // Copyright © 2016 Revo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSDictionary (Collection) 12 | 13 | + (NSDictionary*)fromData:(NSData*)data; 14 | + (NSDictionary*)fromString:(NSString*)string; 15 | - (NSString*)toString; 16 | - (NSDictionary*)except:(NSArray*)exceptKeys; 17 | - (NSDictionary*)only:(NSArray*)keysToKeep; 18 | 19 | - (void)each:(void(^)(id key, id object))operation; 20 | - (NSDictionary*)filter:(BOOL (^)(id key, id object))condition; 21 | - (NSDictionary*)reject:(BOOL (^)(id key, id object))condition; 22 | - (NSDictionary*)map:(id (^)(id key, id object))callback; 23 | @end 24 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Enum(s)/ExpressionPatternTypeObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExpressionPattern.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 20/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef enum { ExpressionPatternTypeEnum_Inequality, 12 | ExpressionPatternTypeEnum_InequalityExtended, 13 | ExpressionPatternTypeEnum_Regex, 14 | 15 | ExpressionPatternTypeEnum_ErrorInitialization 16 | 17 | } ExpressionPatternTypeEnum; 18 | 19 | 20 | @interface ExpressionPatternTypeObject : NSObject 21 | 22 | +(NSString*) getStringFromExpressionPatternType:(ExpressionPatternTypeEnum) enumType; 23 | 24 | +(ExpressionPatternTypeEnum) getEnumValueFromString:(NSString*) enumTypeInString; 25 | 26 | @end 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Enum(s)/InternalPatternObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // InternalPattern.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "InternalPatternObject.h" 10 | 11 | @implementation InternalPatternObject 12 | 13 | +(NSString*) getStringFromInternalPatternEnum:(InternalPatternEnum) enumType 14 | { 15 | NSString *result = nil; 16 | switch(enumType) { 17 | case InternalPatternEnum_Expression: result = @"(?<=\\{)(.+)(?=\\})"; break; 18 | case InternalPatternEnum_ExpressionPatternType: result = @"(^.{2,3})(?=:)"; break; 19 | case InternalPatternEnum_KeyWithoutExpression: result = @"^(.*?)(?=\\{)"; break; 20 | 21 | default: result = @"unknown"; 22 | } 23 | return result; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Enum(s)/InequalitySignObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // InequalitySignObject.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef enum { 12 | InequalitySignEnum_LessThan, 13 | InequalitySignEnum_LessThanOrEqual, 14 | InequalitySignEnum_Equal, 15 | InequalitySignEnum_GreaterThanOrEqual, 16 | InequalitySignEnum_GreaterThan, 17 | 18 | InequalitySignEnum_ErrorInitialization 19 | 20 | } InequalitySignEnum; 21 | 22 | 23 | @interface InequalitySignObject : NSObject 24 | 25 | +(NSString*) getStringFromInequalitySignEnum:(InequalitySignEnum) enumType; 26 | 27 | +(InequalitySignEnum) getEnumValueFromString:(NSString*) enumTypeInString; 28 | 29 | +(InequalitySignEnum) invertWithValue:(InequalitySignEnum) enumValue; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpressionsLoader.m: -------------------------------------------------------------------------------- 1 | // 2 | // SharedExpressionsLoader.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "SharedExpressionsLoader.h" 10 | 11 | @implementation SharedExpressionsLoader 12 | 13 | + (NSArray*)loadExpressions:(NSDictionary*) json 14 | { 15 | __block NSMutableArray* expressions = [NSMutableArray new]; 16 | 17 | [json enumerateKeysAndObjectsUsingBlock:^(id identifier, id pattern, BOOL *stop) { 18 | [expressions addObject: [[SharedExpression alloc]init:identifier andPattern:pattern]]; 19 | }]; 20 | 21 | if (expressions.count > 0){ 22 | return expressions; 23 | } else { 24 | return nil; 25 | } 26 | return expressions; 27 | } 28 | @end 29 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpressionsProcessor.h: -------------------------------------------------------------------------------- 1 | // 2 | // SharedExpressionsProcessor.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | @class SharedExpression; 11 | 12 | typedef NSString CountryCode; 13 | 14 | 15 | @interface SharedExpressionsProcessor : NSObject 16 | 17 | +(NSArray*) processSharedExpression:(CountryCode*) preferedLanguage 18 | andPreferedLanguageExpressions:(NSArray*) preferedLanguageExpressions 19 | andBaseLanguageExpressions:(NSArray*) baseLanguageExpressions; 20 | 21 | +(NSArray*) loadBuiltInExpressions:(CountryCode*) language; 22 | 23 | +(NSArray*) getUniqueObjectsFromToArray:(NSArray*) lhs andRhs:(NSArray*) rhs; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ObjCnalization/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Tests/Pods-ObjCnalization_Tests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Categories/RVCollection.h: -------------------------------------------------------------------------------- 1 | // 2 | // RVCollection.h 3 | // RVCollection 4 | // 5 | // Created by Badchoice on 10/8/16. 6 | // Copyright © 2016 Revo. All rights reserved. 7 | // 8 | 9 | #ifndef RVCollection_h 10 | #define RVCollection_h 11 | 12 | #import "NSArray+HighOrder.h" 13 | #import "NSDictionary+Collection.h" 14 | #import "NSString+Collection.h" 15 | 16 | //#define isEqual(x,y) ((x && [x isEqual:y]) || (!x && !y)) 17 | #define isEqual(x,y) ((!isNull(x) && [x isEqual:y]) || (isNull(x) && isNull(y))) //To avoid new warnings 18 | #define valueOrNull(A) A?A:[NSNull null] 19 | #define valueOr(A,B) isNull(A)?B:A 20 | #define isNull(A) (A == nil || [A isKindOfClass:NSNull.class]) 21 | #define isEmptyString(A) [NSString isEmptyString:A] 22 | #define str(A,...) [NSString stringWithFormat:A,##__VA_ARGS__] 23 | 24 | #ifdef DEBUG 25 | #define DLog(format, ...) NSLog(format, ##__VA_ARGS__) 26 | #else 27 | #define DLog(format, ...) 28 | #endif 29 | 30 | #endif /* Collection_h */ 31 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/Expression.h: -------------------------------------------------------------------------------- 1 | // 2 | // Expression.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 20/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | // Protocols 12 | #import "ExpressionMatcher.h" 13 | 14 | 15 | // TypeAlias in Objective-C 16 | typedef NSString ExpressionPattern; 17 | 18 | 19 | @class LengthVariation; 20 | 21 | #import "ExpressionPatternTypeObject.h" 22 | 23 | @interface Expression : NSObject 24 | 25 | @property (strong, nonatomic) ExpressionPattern* pattern; 26 | @property (strong, nonatomic) NSString* value; 27 | @property (strong, nonatomic) NSMutableArray* lengthVariations; 28 | 29 | @property (strong, nonatomic) id expressionMatcher; 30 | 31 | 32 | - (BOOL) validate:(NSString*) val; 33 | - (ExpressionPatternTypeEnum) getExpressionType:(ExpressionPattern*) pattern; 34 | 35 | - (instancetype)initWithPattern:(NSString*) pattern andValue:(NSString*) value andLenghtVariations:(NSArray*) lengthVariations; 36 | 37 | @end 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Parsers/InequalityExpressionParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // InequalityExpressionParser.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ExpressionParser.h" 11 | #import "InequalitySignObject.h" 12 | #import "Regex.h" 13 | #import "ExpressionPatternTypeObject.h" 14 | #import "InequalityExpressionMatcher.h" 15 | 16 | 17 | 18 | @interface InequalityExpressionParser : NSObject 19 | 20 | @property (nonatomic, strong) ExpressionPattern* pattern; 21 | 22 | - (instancetype)initWithPattern:(NSString*) pattern; 23 | - (id) parse; 24 | 25 | 26 | #pragma mark - Private methods 27 | 28 | - (InequalitySignEnum) sign; 29 | - (double) value; 30 | - (double) getValueWithRegex:(NSString*) regex withFailureMessage:(NSString*) failureMessage withCapturingGroupIdx:(NSInteger) capturingGroupIdx; 31 | - (InequalitySignEnum) getSignWithRegex:(NSString*) regex withFailureMessage:(NSString*) failureMessage withCapturingGroupIdx:(NSInteger) capturingGroupIdx; 32 | @end 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 m1a7 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Parsers/RegexExpressionParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // RegexExpressionParser.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "RegexExpressionParser.h" 10 | 11 | @implementation RegexExpressionParser 12 | 13 | - (instancetype)initWithPattern:(NSString *)pattern 14 | { 15 | self = [super init]; 16 | if (self) { 17 | self.pattern = pattern; 18 | } 19 | return self; 20 | } 21 | 22 | 23 | - (id ) parse 24 | { 25 | NSString* regex = [self regexPattern]; 26 | if (regex){ 27 | return [[RegexExpressionMatcher alloc] initWithPattern:regex]; 28 | } 29 | return nil; 30 | } 31 | 32 | - (RegexPattern*) regexPattern 33 | { 34 | NSString* patternFromEnum = [ExpressionPatternTypeObject getStringFromExpressionPatternType: ExpressionPatternTypeEnum_Regex]; 35 | NSString* regex = [Regex firstMatchInString:self.pattern andPattern:[NSString stringWithFormat:@"(?<=^%@:).*",patternFromEnum]]; 36 | 37 | if (regex){ 38 | return regex; 39 | } 40 | 41 | return nil; 42 | } 43 | 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Matcher(s)/InequalityExpressionMatcher.m: -------------------------------------------------------------------------------- 1 | // 2 | // InequalityExpressionMatcher.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "InequalityExpressionMatcher.h" 10 | 11 | @implementation InequalityExpressionMatcher 12 | 13 | - (instancetype)initWithInequalitySignEnum:(InequalitySignEnum) enumValue withValue:(double) value 14 | { 15 | self = [super init]; 16 | if (self) { 17 | self.sign = enumValue; 18 | self.value = value; 19 | } 20 | return self; 21 | } 22 | 23 | - (BOOL) validate:(NSString *)val 24 | { 25 | double n = val.doubleValue; 26 | 27 | switch(self.sign) { 28 | case InequalitySignEnum_LessThan: return n < self.value; break; 29 | case InequalitySignEnum_LessThanOrEqual: return n <= self.value; break; 30 | case InequalitySignEnum_Equal: return n == self.value; break; 31 | case InequalitySignEnum_GreaterThanOrEqual: return n >= self.value; break; 32 | case InequalitySignEnum_GreaterThan: return n > self.value; break; 33 | 34 | default: break; 35 | } 36 | 37 | return NO; 38 | } 39 | @end 40 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Enum(s)/ExpressionPatternTypeObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExpressionPattern.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 20/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "ExpressionPatternTypeObject.h" 10 | 11 | 12 | @implementation ExpressionPatternTypeObject 13 | 14 | +(NSString*) getStringFromExpressionPatternType:(ExpressionPatternTypeEnum) enumType 15 | { 16 | NSString *result = nil; 17 | switch(enumType) { 18 | case ExpressionPatternTypeEnum_Inequality: result = @"ie"; break; 19 | case ExpressionPatternTypeEnum_InequalityExtended: result = @"iex"; break; 20 | case ExpressionPatternTypeEnum_Regex: result = @"exp"; break; 21 | 22 | default: result = @"unknown"; 23 | } 24 | return result; 25 | } 26 | 27 | +(ExpressionPatternTypeEnum) getEnumValueFromString:(NSString*) enumTypeInString 28 | { 29 | if ([enumTypeInString isEqualToString:@"ie"]) return ExpressionPatternTypeEnum_Inequality; 30 | if ([enumTypeInString isEqualToString:@"iex"]) return ExpressionPatternTypeEnum_InequalityExtended; 31 | if ([enumTypeInString isEqualToString:@"exp"]) return ExpressionPatternTypeEnum_Regex; 32 | else { 33 | 34 | } 35 | 36 | return ExpressionPatternTypeEnum_ErrorInitialization; 37 | } 38 | @end 39 | 40 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Example/Pods-ObjCnalization_Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## ObjCnalization 5 | 6 | Copyright (c) 2017 m1a7 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpression-(Localization)/SharedBaseExpression.m: -------------------------------------------------------------------------------- 1 | // 2 | // SharedBaseExpression.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "SharedBaseExpression.h" 10 | 11 | @implementation SharedBaseExpression 12 | 13 | +(NSArray*) allExpressions 14 | { 15 | NSArray* allExpression = @[ /** 16 | Matches value equals 1. 17 | */ 18 | [[SharedExpression alloc] init:@"one" andPattern:@"ie:x=1"], 19 | 20 | /** 21 | Matches value greater than 1. 22 | */ 23 | [[SharedExpression alloc] init:@">one" andPattern:@"ie:x>1"], 24 | 25 | /** 26 | Matches value equals 2. 27 | */ 28 | [[SharedExpression alloc] init:@"two" andPattern:@"ie:x=2"], 29 | 30 | /** 31 | Matches value other than 1. 32 | */ 33 | [[SharedExpression alloc] init:@"other" andPattern:@"exp:(^[^1])|(^\\d{2,})"]]; 34 | 35 | return allExpression; 36 | } 37 | 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Example/ObjCnalization/localizations/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Glad to see you!", 3 | "book" : "Book", 4 | "car" : "Car", 5 | 6 | "login" : "Login", 7 | "password" : "Password", 8 | "loginTextFieldPlaceHolder" : "enter your login", 9 | "passwordTextFieldPlaceHolder" : "enter your password", 10 | "loginBtn" : "LogIn", 11 | 12 | 13 | "time-seconds": { 14 | "one": "%d second ago", 15 | "other": "%d seconds ago" 16 | }, 17 | 18 | "time-minutes": { 19 | "one": "%d minute ago", 20 | "other": "%d minutes ago" 21 | }, 22 | 23 | "time-hours": { 24 | "one": "%d hours ago", 25 | "other": "%d hours ago" 26 | }, 27 | 28 | 29 | "books" : { 30 | "one" : "%d book", 31 | "other" : "%d books" 32 | }, 33 | 34 | 35 | "forgot-password": { 36 | "@200": "Forgot Password? Help.", 37 | "@300": "Forgot Your Password? Use Help.", 38 | "@400": "Do not remember Your Password? Use Help." 39 | }, 40 | 41 | "cars": { 42 | "one": { 43 | "@100": "One car", 44 | "@200": "You've got one car", 45 | "@300": "You have one automobile" 46 | }, 47 | 48 | "other" : { 49 | "@100": "%d cars", 50 | "@200": "You've got %d cars", 51 | "@300": "You have %d automobile" 52 | } 53 | }, 54 | 55 | "police-cars": { 56 | "exp:^1$" : "1 police car", 57 | "other" : "%d police cars" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Example/ObjCnalization/localizations/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Glad to see you!", 3 | "book" : "Book", 4 | "car" : "Car", 5 | 6 | "login" : "Login", 7 | "password" : "Password", 8 | "loginTextFieldPlaceHolder" : "enter your login", 9 | "passwordTextFieldPlaceHolder" : "enter your password", 10 | "loginBtn" : "LogIn", 11 | 12 | 13 | 14 | "time-seconds": { 15 | "one": "%d second ago", 16 | "other": "%d seconds ago" 17 | }, 18 | 19 | "time-minutes": { 20 | "one": "%d minute ago", 21 | "other": "%d minutes ago" 22 | }, 23 | 24 | "time-hours": { 25 | "one": "%d hours ago", 26 | "other": "%d hours ago" 27 | }, 28 | 29 | 30 | "books" : { 31 | "one" : "%d book", 32 | "other" : "%d books" 33 | }, 34 | 35 | 36 | "forgot-password": { 37 | "@200": "Forgot Password? Help.", 38 | "@300": "Forgot Your Password? Use Help.", 39 | "@400": "Do not remember Your Password? Use Help." 40 | }, 41 | 42 | "cars": { 43 | "one": { 44 | "@100": "One car", 45 | "@200": "You've got one car", 46 | "@300": "You have one automobile" 47 | }, 48 | 49 | "other" : { 50 | "@100": "%d cars", 51 | "@200": "You've got %d cars", 52 | "@300": "You have %d automobile" 53 | } 54 | }, 55 | 56 | "police-cars": { 57 | "exp:^1$" : "1 police car", 58 | "other" : "%d police cars" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/ObjCnalization/ObjCnalization-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "NSArray+Collection.h" 14 | #import "NSArray+HighOrder.h" 15 | #import "NSDictionary+Collection.h" 16 | #import "NSString+Collection.h" 17 | #import "RVCollection.h" 18 | #import "ExpressionPatternTypeObject.h" 19 | #import "InequalitySignObject.h" 20 | #import "InternalPatternObject.h" 21 | #import "Expression.h" 22 | #import "SharedBaseExpression.h" 23 | #import "SharedPolishExpression.h" 24 | #import "SharedRussianExpression.h" 25 | #import "SharedExpression.h" 26 | #import "SharedExpressionsLoader.h" 27 | #import "SharedExpressionsProcessor.h" 28 | #import "LengthVariation.h" 29 | #import "JSONFileLoader.h" 30 | #import "InequalityExpressionMatcher.h" 31 | #import "InequalityExtendedExpressionMatcher.h" 32 | #import "RegexExpressionMatcher.h" 33 | #import "ObjCnalization.h" 34 | #import "InequalityExpressionParser.h" 35 | #import "InequalityExtendedExpressionParser.h" 36 | #import "RegexExpressionParser.h" 37 | #import "ExpressionMatcher.h" 38 | #import "ExpressionParser.h" 39 | #import "Regex.h" 40 | #import "LoadedTranslation.h" 41 | #import "LoadedTranslationsProcessor.h" 42 | #import "LoadedTranslationTypeObject.h" 43 | #import "TranslationsLoader.h" 44 | #import "Translation.h" 45 | 46 | FOUNDATION_EXPORT double ObjCnalizationVersionNumber; 47 | FOUNDATION_EXPORT const unsigned char ObjCnalizationVersionString[]; 48 | 49 | -------------------------------------------------------------------------------- /Example/ObjCnalization/RXViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RXViewController.m 3 | // ObjCnalization 4 | // 5 | // Created by m1a7 on 12/04/2017. 6 | // Copyright (c) 2017 m1a7. All rights reserved. 7 | // 8 | 9 | #import "RXViewController.h" 10 | #import 11 | 12 | @interface RXViewController () 13 | @property (weak, nonatomic) IBOutlet UILabel *welcomeLabel; 14 | @property (weak, nonatomic) IBOutlet UILabel *loginLabel; 15 | @property (weak, nonatomic) IBOutlet UILabel *passwordLabel; 16 | 17 | @property (weak, nonatomic) IBOutlet UITextField *loginTextField; 18 | @property (weak, nonatomic) IBOutlet UITextField *passwrodTextField; 19 | 20 | @property (weak, nonatomic) IBOutlet UIButton *loginBtn; 21 | @property (weak, nonatomic) IBOutlet UIButton *forgotPasswordBtn; 22 | @end 23 | 24 | @implementation RXViewController 25 | 26 | - (void) viewDidAppear:(BOOL)animated 27 | { 28 | [super viewDidAppear:animated]; 29 | 30 | self.welcomeLabel.text = [[I18n sharedInstance] localizedString:@"welcome"]; 31 | self.loginLabel.text = [[I18n sharedInstance] localizedString:@"login"]; 32 | self.passwordLabel.text = [[I18n sharedInstance] localizedString:@"password"]; 33 | 34 | self.loginTextField.placeholder = [[I18n call] locStr:@"loginTextFieldPlaceHolder"]; 35 | self.passwrodTextField.placeholder = [[I18n call] locStr:@"passwordTextFieldPlaceHolder"]; 36 | 37 | [self.loginBtn setTitle: [[I18n call] locStr:@"loginBtn"] forState:UIControlStateNormal]; 38 | [self.forgotPasswordBtn setTitle: [[I18n call] locStr:@"forgot-password"] forState:UIControlStateNormal]; 39 | 40 | } 41 | @end 42 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpression-(Localization)/SharedPolishExpression.m: -------------------------------------------------------------------------------- 1 | // 2 | // SharedPolishExpression.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "SharedPolishExpression.h" 10 | 11 | @implementation SharedPolishExpression 12 | 13 | +(NSArray*) allExpressions 14 | { 15 | NSArray* allExpression = @[ 16 | /** 17 | (2-4), (22-24), (32-4), ..., (..>22, ..>23, ..>24) 18 | 19 | e.g. 20 | - 22 samochody, 1334 samochody, 53 samochody 21 | - 2 minuty, 4 minuty, 23 minuty 22 | */ 23 | [[SharedExpression alloc] init:@"few" andPattern:@"exp:(((?!1).[2-4]{1})$)|(^[2-4]$)"], 24 | 25 | /** 26 | 0, (5-9), (10-21), (25-31), ..., (..0, ..1, ..5-9) 27 | 28 | e.g. 29 | - 0 samochodów, 10 samochodów, 26 samochodów, 1147 samochodów 30 | - 5 minut, 18 minut, 117 minut, 1009 minut 31 | */ 32 | [[SharedExpression alloc] init:@"many" andPattern:@"exp:(^[05-9]$)|(.*(?=1).[0-9]$)|(^[0-9]{1}.*[0156789]$)"] 33 | 34 | ]; 35 | 36 | return allExpression; 37 | } 38 | 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Example/ObjCnalization/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/ObjCnalization/ObjCnalization-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Loader(s)/JSONFileLoader.m: -------------------------------------------------------------------------------- 1 | // 2 | // JSONFileLoader.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "JSONFileLoader.h" 10 | 11 | @implementation JSONFileLoader 12 | 13 | + (JSONDictionary*) loadTranslations:(CountryCode*) countryCode andBundle:(NSBundle*) bundle 14 | { 15 | NSDictionary* dict = [self load:countryCode andBundle:bundle]; 16 | if (dict){ 17 | return dict; 18 | } 19 | return @{}; 20 | } 21 | 22 | + (NSDictionary*) loadExpressions:(CountryCode*) countryCode andBundle:(NSBundle*) bundle 23 | { 24 | JSONDictionary* dict = [self load:@"expressions" andBundle:bundle]; 25 | 26 | if (dict){ 27 | JSONDictionary* internalDict = dict[countryCode]; 28 | if (internalDict){ 29 | return internalDict; 30 | }else { 31 | return @{}; 32 | } 33 | } 34 | return nil; 35 | } 36 | 37 | + (JSONDictionary*) load:(NSString*) fileName andBundle:(NSBundle*) bundle 38 | { 39 | NSURL* fileURL = [bundle URLForResource:fileName withExtension:@"json"]; 40 | 41 | if (fileURL){ 42 | return [self load:fileURL]; 43 | } 44 | return nil; 45 | } 46 | 47 | 48 | + (JSONDictionary*) load:(NSURL*) fileURL 49 | { 50 | NSData* data = [NSData dataWithContentsOfURL:fileURL]; 51 | if (data) 52 | { 53 | NSError *errorTransformJsonToDict = nil; 54 | NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &errorTransformJsonToDict]; 55 | if (dictionary) 56 | { 57 | return dictionary; 58 | } 59 | return nil; 60 | } 61 | return nil; 62 | } 63 | 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /ObjCnalization.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint ObjCnalization.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'ObjCnalization' 11 | s.version = '0.2.0' 12 | s.summary = 'Localize iOS apps in a smarter way using JSON files. ObjC framework.' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = 'ObjC library that helps in localizing apps in a different, better, simpler, more powerful way than system localization does' 21 | #TODO: Add long description of the pod here. 22 | 23 | 24 | s.homepage = 'https://github.com/m1a7/ObjCnalization' 25 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 26 | s.license = { :type => 'MIT', :file => 'LICENSE' } 27 | s.author = { 'm1a7' => 'thisismymail03@gmail.com' } 28 | s.source = { :git => 'https://github.com/m1a7/ObjCnalization.git', :tag => s.version.to_s } 29 | 30 | s.ios.deployment_target = '8.0' 31 | 32 | s.source_files = 'ObjCnalization/Classes/**/*.{h,m}' 33 | 34 | # s.resource_bundles = { 35 | # 'ObjCnalization' => ['ObjCnalization/Assets/*.png'] 36 | # } 37 | 38 | # s.public_header_files = 'Pod/Classes/**/*.h' 39 | # s.frameworks = 'UIKit', 'MapKit' 40 | # s.dependency 'AFNetworking', '~> 2.3' 41 | end 42 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Categories/NSArray+HighOrder/NSArray+HighOrder.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+HighOrder.m 3 | // Collection 4 | // 5 | // Created by Badchoice on 10/10/17. 6 | // Copyright © 2017 Revo. All rights reserved. 7 | // 8 | 9 | #import "NSArray+HighOrder.h" 10 | 11 | @implementation NSArray (HighOrder) 12 | 13 | #pragma clang diagnostic push 14 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 15 | 16 | -(NSArray*)map_:(SEL)selector{ 17 | return [self map:^id(id obj, NSUInteger idx) { 18 | return [obj performSelector:selector]; 19 | }]; 20 | } 21 | 22 | -(NSArray*)map_:(SEL)selector withObject:(id)object{ 23 | return [self map:^id(id obj, NSUInteger idx) { 24 | return [obj performSelector:selector withObject:object]; 25 | }]; 26 | } 27 | 28 | -(void)each_:(SEL)selector{ 29 | [self each:^(id object) { 30 | [object performSelector:selector]; 31 | }]; 32 | } 33 | 34 | -(void)each_:(SEL)selector withObject:(id)object{ 35 | [self each:^(id object) { 36 | [object performSelector:selector withObject:object]; 37 | }]; 38 | } 39 | 40 | -(NSArray*)filter_:(SEL)selector{ 41 | return [self filter:^BOOL(id object) { 42 | return (BOOL)[object performSelector:selector]; 43 | }]; 44 | } 45 | 46 | -(NSArray*)filter_:(SEL)selector withObject:(id)object{ 47 | return [self filter:^BOOL(id obj) { 48 | return (BOOL)[obj performSelector:selector withObject:object]; 49 | }]; 50 | } 51 | 52 | -(NSArray*)reject_:(SEL)selector{ 53 | return [self reject:^BOOL(id object) { 54 | return (BOOL)[object performSelector:selector]; 55 | }]; 56 | } 57 | 58 | -(NSArray*)reject_:(SEL)selector withObject:(id)object{ 59 | return [self reject:^BOOL(id obj) { 60 | return (BOOL)[obj performSelector:selector withObject:object]; 61 | }]; 62 | } 63 | 64 | #pragma clang diagnostic pop 65 | @end 66 | -------------------------------------------------------------------------------- /Example/ObjCnalization/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Example/ObjCnalization/RXAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // RXAppDelegate.m 3 | // ObjCnalization 4 | // 5 | // Created by m1a7 on 12/04/2017. 6 | // Copyright (c) 2017 m1a7. All rights reserved. 7 | // 8 | 9 | #import "RXAppDelegate.h" 10 | #import 11 | 12 | @implementation RXAppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 15 | { 16 | [[ObjCnalization sharedInstance] configure:[NSBundle mainBundle]]; 17 | 18 | NSString* welcome = [[ObjCnalization sharedInstance] localizedString:@"welcome"]; 19 | NSString* book = [[ObjCnalization sharedInstance] localizedString:@"book"]; 20 | NSString* timeSeconds = [[ObjCnalization sharedInstance] localizedString:@"time-seconds" andIntVal:60]; 21 | NSString* timeMinutes = [[ObjCnalization sharedInstance] localizedString:@"time-minutes" andIntVal:21]; 22 | NSString* timeHours = [[ObjCnalization sharedInstance] localizedString:@"time-hours" andIntVal:3]; 23 | 24 | NSString* books = [[ObjCnalization sharedInstance] localizedString:@"books" andIntVal:21]; 25 | NSString* forgotPassword = [[ObjCnalization sharedInstance] localizedString:@"forgot-password" andFittWidth:300]; 26 | 27 | NSString* cars = [[ObjCnalization sharedInstance] localizedString:@"cars" andIntVal:32 andFittWidth:200]; 28 | NSString* policeCars = [[ObjCnalization sharedInstance] localizedString:@"police-cars" andIntVal:471 andFittWidth:0]; 29 | 30 | 31 | NSLog(@"welcome = %@",welcome); 32 | NSLog(@"book = %@",book); 33 | 34 | NSLog(@"timeSeconds = %@",timeSeconds); 35 | NSLog(@"timeMinutes = %@",timeMinutes); 36 | NSLog(@"timeHours = %@",timeHours); 37 | 38 | NSLog(@"books = %@",books); 39 | NSLog(@"forgotPassword = %@",forgotPassword); 40 | 41 | NSLog(@"cars = %@",cars); 42 | NSLog(@"policeCars = %@",policeCars); 43 | 44 | return YES; 45 | } 46 | 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Translation.m: -------------------------------------------------------------------------------- 1 | // 2 | // Translation.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "Translation.h" 10 | #import "Expression.h" 11 | #import "LengthVariation.h" 12 | 13 | @implementation Translation 14 | 15 | - (NSString*) validate:(NSString*) text andFittingWidth:(NSInteger) fittingWidth 16 | { 17 | for (Expression* expression in self.expressions) { 18 | 19 | if ([expression validate:text]) 20 | { 21 | NSString* localizedValue = expression.value; 22 | 23 | if (fittingWidth != NSNotFound && expression.lengthVariations.count > 0) 24 | { 25 | 26 | NSSortDescriptor* sortOrder = [NSSortDescriptor sortDescriptorWithKey: @"width" 27 | ascending: YES]; 28 | NSArray *lengthVariations = [expression.lengthVariations sortedArrayUsingDescriptors: @[sortOrder]]; 29 | 30 | for (LengthVariation* variation in lengthVariations) { 31 | 32 | if (variation.width <= fittingWidth){ 33 | localizedValue = variation.value; 34 | } 35 | } 36 | } 37 | NSString* newStr = [localizedValue stringByReplacingOccurrencesOfString:@"%d" 38 | withString:text]; 39 | if (newStr.length > 0) { 40 | return newStr; 41 | } 42 | return localizedValue; 43 | } 44 | } 45 | return @"The value not found!"; 46 | } 47 | 48 | - (instancetype)initWithKey:(NSString*) key andExpressions:(NSArray*) expressions 49 | { 50 | self = [super init]; 51 | if (self) { 52 | self.key = key; 53 | self.expressions = [NSArray arrayWithArray:expressions]; 54 | } 55 | return self; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /Example/ObjCnalization/localizations/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Miło cię widzieć", 3 | "book" : "Książka", 4 | "car" : "Maszyna", 5 | 6 | "login" : "Login", 7 | "password" : "Hasło", 8 | "loginTextFieldPlaceHolder" : "Wprowadź login", 9 | "passwordTextFieldPlaceHolder" : "Wprowadź hasło", 10 | "loginBtn" : "Zaloguj się", 11 | 12 | "time-seconds": { 13 | "one": "1 sekundę temu", 14 | "few": "%d sekundy temu", 15 | "many": "%d sekund temu" 16 | }, 17 | 18 | "time-minutes": { 19 | "one": "1 minutę temu", 20 | "few": "%d minuty temu", 21 | "many": "%d minut temu" 22 | }, 23 | 24 | "time-hours": { 25 | "one": "1 godzinę temu", 26 | "few": "%d godziny temu", 27 | "many": "%d godzin temu" 28 | }, 29 | 30 | 31 | 32 | 33 | "books" : { 34 | "one" : "%d książka", 35 | "few" : "%d książki", 36 | "many": "%d książek" 37 | }, 38 | 39 | "forgot-password": { 40 | "@200": "Nie Pamiętasz Hasła? Pomóc.", 41 | "@300": "Nie Pamiętasz Hasła? Skorzystaj Z Pomocy.", 42 | "@400": "Nie pamiętasz hasła? Skorzystaj Z Pomocy." 43 | }, 44 | 45 | 46 | "cars": { 47 | "ie:x=1": { 48 | "@100": "Jeden samochód", 49 | "@200": "Masz jedno auto", 50 | "@300": "Masz jeden samochód" 51 | }, 52 | 53 | "few" : { 54 | "@100": "%d auta", 55 | "@200": "Masz %d auto", 56 | "@300": "Masz %d samochodu" 57 | }, 58 | 59 | "many" : { 60 | "@100": "%d samochodów", 61 | "@200": "Masz %d auto", 62 | "@300": "Masz %d samochodów" 63 | }, 64 | 65 | "more": "Masz kilka maszyn" 66 | }, 67 | 68 | 69 | "police-cars": { 70 | "exp:^1$": "1 samochód policyjny", 71 | "exp:(((?!1).[2-4]{1})$)|(^[2-4]$)": "%d samochody policyjne", 72 | "exp:(.*(?=1).[0-9]$)|(^[05-9]$)|(.*(?!1).[0156789])": "%d samochodów policyjnych" 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Categories/NSString+Collection/NSString+Collection.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Collection.h 3 | // Collection 4 | // 5 | // Created by Jordi Puigdellívol on 10/8/16. 6 | // Copyright © 2016 Revo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (Collection) 12 | 13 | + (NSString*)repeat:(NSString*)text times:(int)times; 14 | + (BOOL)isEmptyString:(NSString*)string; 15 | 16 | - (NSArray*) explode:(NSString*)delimiter; 17 | - (NSString*) initials; 18 | - (NSNumber*) toNumber; 19 | - (NSString*) append:(NSString*)append; 20 | - (NSString*) prepend:(NSString*)prepend; 21 | - (NSString*) substr:(int)from; 22 | - (NSString*) substr:(int)from length:(int)length; 23 | 24 | - (NSString*)replace:(NSString*)character with:(NSString*)replace; 25 | 26 | - (NSArray*) split; 27 | - (NSArray*) split:(int)splitLength; 28 | 29 | 30 | /** 31 | Trims spaces on both ends 32 | */ 33 | - (NSString*) trim; 34 | 35 | /** 36 | Trims spaces and new line characters on both ends 37 | */ 38 | - (NSString*) trimWithNewLine; 39 | 40 | - (NSString*) trimLeft; 41 | - (NSString*) trimRight; 42 | 43 | /** 44 | * Converts @"this text" to @"thisText" or @"a_text" to @"aText" 45 | */ 46 | - (NSString *)camelCase; 47 | 48 | /** 49 | * Converts @"this text" to @"ThisText" or @"a_text" to @"AText" 50 | */ 51 | - (NSString *)pascalCase; 52 | 53 | /** 54 | Converts @"fooBar" to @"foo_bar" 55 | */ 56 | - (NSString *)snakeCase; 57 | 58 | /** 59 | * Capitalizes first letter 60 | */ 61 | - (NSString *)ucFirst; 62 | 63 | /** 64 | * Lowercases first letter 65 | */ 66 | - (NSString *)lcFirst; 67 | 68 | - (NSString*)withoutDiacritic; 69 | 70 | - (NSString*) urlEncode; 71 | - (NSString*) urlDecode; 72 | - (NSString*) md5; 73 | - (NSString*) toBase64; 74 | //+ (NSString*) fromBase64; 75 | + (NSString*) fromHex:(NSString *)str; 76 | - (NSString*) toHex; 77 | 78 | -(BOOL)endsWith: (NSString*)compare; 79 | -(BOOL)startsWith: (NSString*)compare; 80 | -(BOOL)contains: (NSString*)compare; 81 | -(BOOL)matches: (NSString*)regexp; 82 | 83 | -(NSString*)lpad:(int)lenght string:(NSString*)string; 84 | -(NSString*)rpad:(int)lenght string:(NSString*)string; 85 | @end 86 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Translation(s)/TranslationsLoader.m: -------------------------------------------------------------------------------- 1 | // 2 | // TranslationsLoader.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "TranslationsLoader.h" 10 | 11 | @implementation TranslationsLoader 12 | 13 | #pragma mark - Public methods 14 | 15 | + (NSArray*) loadTranslations:(NSDictionary*) json 16 | { 17 | NSMutableArray* loadedTranslations = [NSMutableArray new]; 18 | __weak NSMutableArray* weakArray = loadedTranslations; 19 | 20 | [json enumerateKeysAndObjectsUsingBlock:^(NSString* key, id value, BOOL *stop) { 21 | 22 | if ([value isKindOfClass:[NSString class]]) 23 | { 24 | [weakArray addObject: [[LoadedTranslation alloc] initWithType:LoadedTranslationTypeEnum_Simple andKey:key andContent:@{key:value}]]; 25 | } else { 26 | JSONDictionary* dictionary = (JSONDictionary*)value; 27 | LoadedTranslationTypeEnum type = [TranslationsLoader detectElementType:dictionary]; 28 | 29 | if(type != NSNotFound){ 30 | [weakArray addObject: [[LoadedTranslation alloc] initWithType:type andKey:key andContent:dictionary]]; 31 | } 32 | } 33 | }]; 34 | return loadedTranslations; 35 | } 36 | 37 | #pragma mark - Private methods 38 | + (LoadedTranslationTypeEnum) detectElementType:(JSONDictionary*) element 39 | { 40 | int dicts = 0; 41 | int strings = 0; 42 | 43 | for (id value in [element allValues]) { 44 | 45 | if ([value isKindOfClass:[NSString class]]) 46 | strings += 1; 47 | else if ([value isKindOfClass:[NSDictionary class]]) 48 | dicts += 1; 49 | } 50 | 51 | if(strings > 0 && dicts == 0) 52 | { 53 | NSString* key = [element.allKeys firstObject]; 54 | 55 | return [[key substringToIndex:1] isEqualToString:@"@"] ? LoadedTranslationTypeEnum_WithLengthVariations : LoadedTranslationTypeEnum_WithExpressions; 56 | 57 | } else if (strings >= 0 && dicts > 0) { 58 | return LoadedTranslationTypeEnum_WithExpressionsAndLengthVariations; 59 | } 60 | return 0; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /Example/ObjCnalization/localizations/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcome": "Добро пожаловать!", 3 | "book" : "Книга", 4 | "car" : "Машина", 5 | 6 | "login" : "Логин", 7 | "password" : "Пароль", 8 | "loginTextFieldPlaceHolder" : "Введите логин", 9 | "passwordTextFieldPlaceHolder" : "Введите пароль", 10 | "loginBtn" : "Войти", 11 | 12 | "time-seconds": { 13 | "one": "%d секунда назад", 14 | "few": "%d секунды назад", 15 | "many":"%d секунд назад" 16 | }, 17 | 18 | "time-minutes": { 19 | "one": "%d минута назад", 20 | "few": "%d минуты назад", 21 | "many":"%d минут назад" 22 | }, 23 | 24 | "time-hours": { 25 | "one" : "%d час назад", 26 | "few" : "%d часа назад", 27 | "many": "%d часов назад" 28 | }, 29 | 30 | 31 | "books" : { 32 | "one" : "%d книга", 33 | "few" : "%d книги", 34 | "many": "%d книг" 35 | }, 36 | 37 | "forgot-password": { 38 | "@200": "Забыли Пароль? Помочь.", 39 | "@300": "Забыли Пароль? Используйте Помощь.", 40 | "@400": "Забыли Пароль? Воспользуйтесь помощью." 41 | }, 42 | 43 | "cars": { 44 | "ie:x=1": { 45 | "@100": "Один автомобиль", 46 | "@200": "У вас есть одно авто", 47 | "@300": "У вас есть один автомобиль" 48 | }, 49 | "one" : { 50 | "@100" : "%d машина", 51 | "@200" : "У вас есть %d машина", 52 | }, 53 | 54 | "few" : { 55 | "@100": "%d автомобиля", 56 | "@200": "У вас есть %d авто", 57 | "@300": "У вас есть %d автомобиля" 58 | }, 59 | 60 | "many" : { 61 | "@100": "%d автомобилей", 62 | "@200": "У вас есть %d авто", 63 | "@300": "У вас есть %d автомобилей" 64 | }, 65 | "more": "У вас есть несколько машин" 66 | }, 67 | 68 | "police-cars": { 69 | "exp:(^1$)|(^[^1]1$)|(^[1-9][0-9]?[0,2,3,4,5,6,7,8,9]+1$)": "%d полицейское авто", 70 | "exp:(((?!1).[2-4]{1})$)|(^[2-4]$)": "%d полицейских авто", 71 | "exp:(.*(?=1).[0-9]$)|(^[05-9]$)|(.*(?!1).[0156789])": "%d полицейских автомобиля" 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Enum(s)/InequalitySignObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // InequalitySignObject.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "InequalitySignObject.h" 10 | 11 | 12 | @implementation InequalitySignObject 13 | 14 | +(NSString*) getStringFromInequalitySignEnum:(InequalitySignEnum) enumType 15 | { 16 | NSString *result = nil; 17 | switch(enumType) { 18 | case InequalitySignEnum_LessThan: result = @"<"; break; 19 | case InequalitySignEnum_LessThanOrEqual: result = @"<="; break; 20 | case InequalitySignEnum_Equal: result = @"="; break; 21 | case InequalitySignEnum_GreaterThanOrEqual: result = @">="; break; 22 | case InequalitySignEnum_GreaterThan: result = @">"; break; 23 | 24 | default: result = @"unknown"; 25 | } 26 | return result; 27 | } 28 | 29 | +(InequalitySignEnum) getEnumValueFromString:(NSString*) enumTypeInString 30 | { 31 | if ([enumTypeInString isEqualToString:@"<"]) return InequalitySignEnum_LessThan; 32 | if ([enumTypeInString isEqualToString:@"<="]) return InequalitySignEnum_LessThanOrEqual; 33 | if ([enumTypeInString isEqualToString:@"="]) return InequalitySignEnum_Equal; 34 | if ([enumTypeInString isEqualToString:@">="]) return InequalitySignEnum_GreaterThanOrEqual; 35 | if ([enumTypeInString isEqualToString:@">"]) return InequalitySignEnum_GreaterThan; 36 | 37 | return InequalitySignEnum_ErrorInitialization; 38 | } 39 | 40 | +(InequalitySignEnum) invertWithValue:(InequalitySignEnum) enumValue 41 | { 42 | switch(enumValue) { 43 | case InequalitySignEnum_LessThan: return InequalitySignEnum_GreaterThan; break; 44 | case InequalitySignEnum_LessThanOrEqual: return InequalitySignEnum_GreaterThanOrEqual; break; 45 | case InequalitySignEnum_Equal: return InequalitySignEnum_Equal; break; 46 | case InequalitySignEnum_GreaterThanOrEqual: return InequalitySignEnum_LessThanOrEqual; break; 47 | case InequalitySignEnum_GreaterThan: return InequalitySignEnum_LessThan; break; 48 | 49 | default: break; 50 | } 51 | 52 | return InequalitySignEnum_ErrorInitialization; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Example/Pods-ObjCnalization_Example-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2017 m1a7 <thisismymail03@gmail.com> 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | ObjCnalization 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpression-(Localization)/SharedRussianExpression.m: -------------------------------------------------------------------------------- 1 | // 2 | // SharedRussianExpression.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "SharedRussianExpression.h" 10 | 11 | @implementation SharedRussianExpression 12 | 13 | +(NSArray*) allExpressions 14 | { 15 | NSArray* allExpression = @[ 16 | /** 17 | 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … 18 | 19 | v = 0 and 20 | i % 10 = 1 and 21 | i % 100 != 11 22 | 23 | e.g. 24 | - из 1 книги за 1 день 25 | */ 26 | [[SharedExpression alloc] init:@"one" andPattern:@"exp:(^1$)|(^[^1]1$)|(^[1-9][0-9]?[0,2,3,4,5,6,7,8,9]+1$)"], 27 | 28 | 29 | /** 30 | 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … 31 | 32 | v = 0 and 33 | i % 10 = 2..4 and 34 | i % 100 != 12..14 35 | 36 | e.g. 37 | - из 2 книг за 2 дня 38 | */ 39 | [[SharedExpression alloc] init:@"few" andPattern:@"exp:(^[2-4]$)|(^[2-9][2-4]$)|([1-9]+[0-9]*[^1][2-4]$)"], 40 | 41 | /** 42 | 0, 5~20, 100, 1000, 10000, 100000, 1000000, … 43 | 44 | v = 0 and 45 | i % 10 = 0 or 46 | v = 0 and 47 | i % 10 = 5..9 or 48 | v = 0 and 49 | i % 100 = 11..14 50 | 51 | e.g. 52 | - из 5 книг за 5 дней 53 | */ 54 | [[SharedExpression alloc] init:@"many" andPattern:@"exp:(^[05-9]$)|(^1[1-4]$)|(^[1-9]+[0-9]*[5-9]$)|(^[1-9]+[0-9]*1{1}[1-4]$)|([1-9]+[0-9]*0$)"] 55 | ]; 56 | 57 | return allExpression; 58 | } 59 | 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/Expression.m: -------------------------------------------------------------------------------- 1 | // 2 | // Expression.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 20/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "Expression.h" 10 | 11 | #import "LengthVariation.h" 12 | #import "Regex.h" 13 | #import "InternalPatternObject.h" 14 | #import "InequalityExpressionParser.h" 15 | #import "InequalityExtendedExpressionParser.h" 16 | #import "RegexExpressionParser.h" 17 | 18 | @implementation Expression 19 | 20 | 21 | - (instancetype)initWithPattern:(NSString*) pattern andValue:(NSString*) value andLenghtVariations:(NSArray*) lengthVariations 22 | { 23 | self = [super init]; 24 | if (self) { 25 | 26 | self.pattern = pattern; 27 | self.value = value; 28 | 29 | if (lengthVariations){ 30 | self.lengthVariations = [NSMutableArray arrayWithArray:lengthVariations]; 31 | } 32 | 33 | ExpressionPatternTypeEnum enumExpression = [self getExpressionType:pattern]; 34 | 35 | 36 | if (enumExpression == ExpressionPatternTypeEnum_ErrorInitialization){ 37 | 38 | } 39 | 40 | if (enumExpression){ 41 | switch(enumExpression) { 42 | case ExpressionPatternTypeEnum_Inequality: self.expressionMatcher = [[[InequalityExpressionParser alloc] initWithPattern:pattern] parse]; break; 43 | case ExpressionPatternTypeEnum_InequalityExtended: self.expressionMatcher = [[[InequalityExtendedExpressionParser alloc] initWithPattern: pattern] parse]; break; 44 | case ExpressionPatternTypeEnum_Regex: self.expressionMatcher = [[[RegexExpressionParser alloc] initWithPattern:pattern] parse]; break; 45 | 46 | case ExpressionPatternTypeEnum_ErrorInitialization: break; 47 | 48 | default: break; 49 | } 50 | } 51 | } 52 | return self; 53 | } 54 | 55 | 56 | - (BOOL) validate:(NSString*) val 57 | { 58 | if (self.expressionMatcher){ 59 | return [self.expressionMatcher validate:val]; 60 | } 61 | return [self.pattern isEqualToString:val]; 62 | } 63 | 64 | - (ExpressionPatternTypeEnum) getExpressionType:(ExpressionPattern*) pattern 65 | { 66 | NSString* patternForRegex = [InternalPatternObject getStringFromInternalPatternEnum: InternalPatternEnum_ExpressionPatternType]; 67 | NSString* result = [Regex firstMatchInString:pattern andPattern:patternForRegex]; 68 | 69 | if (result){ 70 | return [ExpressionPatternTypeObject getEnumValueFromString:result]; 71 | } 72 | 73 | return ExpressionPatternTypeEnum_ErrorInitialization; 74 | } 75 | 76 | 77 | 78 | @end 79 | 80 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Parsers/InequalityExpressionParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // InequalityExpressionParser.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "InequalityExpressionParser.h" 10 | 11 | @implementation InequalityExpressionParser 12 | 13 | - (instancetype)initWithPattern:(NSString*) pattern; 14 | { 15 | self = [super init]; 16 | if (self) { 17 | self.pattern = pattern; 18 | } 19 | return self; 20 | } 21 | 22 | 23 | - (id) parse 24 | { 25 | InequalitySignEnum sign = [self sign]; 26 | double value = [self value]; 27 | 28 | 29 | if (sign && value){ 30 | return [[InequalityExpressionMatcher alloc] initWithInequalitySignEnum:sign withValue:value]; 31 | } 32 | return nil; 33 | } 34 | 35 | 36 | #pragma mark - Private methods 37 | 38 | - (InequalitySignEnum) sign 39 | { 40 | NSString* fullRegex = [NSString stringWithFormat:@"%@%@", [ExpressionPatternTypeObject getStringFromExpressionPatternType: 41 | ExpressionPatternTypeEnum_Inequality], 42 | @":x(<=|<|=|>=|>)"]; 43 | 44 | return [self getSignWithRegex:fullRegex withFailureMessage:@"Cannot find any sign" withCapturingGroupIdx:1]; 45 | } 46 | 47 | 48 | - (double) value 49 | { 50 | NSString* fullRegex = [NSString stringWithFormat:@"%@%@", [ExpressionPatternTypeObject getStringFromExpressionPatternType: 51 | ExpressionPatternTypeEnum_Inequality], 52 | @":x[^-\\d]{1,2}(-?\\d+[.]{0,1}[\\d]{0,})"]; 53 | 54 | return [self getValueWithRegex:fullRegex withFailureMessage:@"Cannot find any value" withCapturingGroupIdx:1]; 55 | } 56 | 57 | 58 | 59 | - (double) getValueWithRegex:(NSString*) regex withFailureMessage:(NSString*) failureMessage withCapturingGroupIdx:(NSInteger) capturingGroupIdx 60 | { 61 | NSString* value = [Regex matchInString:self.pattern andPattern:regex andCapturingGroupIdx:capturingGroupIdx]; 62 | 63 | if (value){ 64 | return [value doubleValue]; 65 | } else 66 | 67 | return 0; 68 | } 69 | 70 | 71 | - (InequalitySignEnum) getSignWithRegex:(NSString*) regex withFailureMessage:(NSString*) failureMessage withCapturingGroupIdx:(NSInteger) capturingGroupIdx 72 | { 73 | NSString* rawValue = [Regex matchInString:self.pattern andPattern:regex andCapturingGroupIdx:capturingGroupIdx]; 74 | InequalitySignEnum sign = [InequalitySignObject getEnumValueFromString:rawValue]; 75 | 76 | if (sign){ 77 | return sign; 78 | } 79 | 80 | return InequalitySignEnum_ErrorInitialization; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Expression(s)/SharedExpressionsProcessor.m: -------------------------------------------------------------------------------- 1 | // 2 | // SharedExpressionsProcessor.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "SharedExpressionsProcessor.h" 10 | #import "SharedExpression.h" 11 | //#import 12 | 13 | #import "NSArray+Collection.h" 14 | #import "NSArray+HighOrder.h" 15 | 16 | #import "SharedBaseExpression.h" 17 | #import "SharedPolishExpression.h" 18 | #import "SharedRussianExpression.h" 19 | 20 | 21 | @implementation SharedExpressionsProcessor 22 | 23 | +(NSArray*) processSharedExpression:(CountryCode*) preferedLanguage 24 | andPreferedLanguageExpressions:(NSArray*) preferedLanguageExpressions 25 | andBaseLanguageExpressions:(NSArray*) baseLanguageExpressions 26 | { 27 | NSArray* uniqueBaseExpressions = [self getUniqueObjectsFromToArray:baseLanguageExpressions andRhs:preferedLanguageExpressions]; 28 | 29 | NSArray* loadedExpressions = [uniqueBaseExpressions arrayByAddingObjectsFromArray:preferedLanguageExpressions]; 30 | 31 | NSArray* prefBuiltInExpressions = [SharedExpressionsProcessor loadBuiltInExpressions:preferedLanguage]; 32 | 33 | NSArray* baseBuiltInExpressions = [SharedBaseExpression allExpressions]; 34 | 35 | NSArray* uniqueBaseBuiltInExpressions = [self getUniqueObjectsFromToArray:baseBuiltInExpressions andRhs:prefBuiltInExpressions]; 36 | 37 | NSArray* builtInExpressions = [uniqueBaseBuiltInExpressions arrayByAddingObjectsFromArray:prefBuiltInExpressions]; 38 | 39 | return [loadedExpressions arrayByAddingObjectsFromArray: [self getUniqueObjectsFromToArray:builtInExpressions andRhs:loadedExpressions]]; 40 | } 41 | 42 | +(NSArray*) loadBuiltInExpressions:(CountryCode*) language 43 | { 44 | if ([language isEqualToString:@"pl"]) return [SharedPolishExpression allExpressions]; 45 | if ([language isEqualToString:@"ru"]) return [SharedRussianExpression allExpressions]; 46 | return nil; 47 | } 48 | 49 | 50 | +(NSArray*) getUniqueObjectsFromToArray:(NSArray*) lhs andRhs:(NSArray*) rhs 51 | { 52 | NSMutableArray* result = [NSMutableArray arrayWithArray:lhs]; 53 | 54 | if (rhs.count > 0) 55 | { 56 | result = (NSMutableArray*)[lhs filter:^BOOL(SharedExpression* objectLhs) { 57 | 58 | return [[rhs filter:^BOOL(SharedExpression* objectRhs) { 59 | return [objectLhs.identifier isEqualToString:objectRhs.identifier]; 60 | }] count] == 0; 61 | }]; 62 | } 63 | return result; 64 | } 65 | 66 | @end 67 | 68 | 69 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Regex.m: -------------------------------------------------------------------------------- 1 | // 2 | // Regex.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "Regex.h" 10 | 11 | @implementation Regex 12 | 13 | 14 | + (NSString*) matchInString:(NSString*) str andPattern:(NSString*) pattern andCapturingGroupIdx:(NSInteger)capturingGroupIdx 15 | { 16 | __block NSString* resultString; 17 | 18 | NSRange range = NSMakeRange(0, str.length); 19 | 20 | NSRegularExpression* regExp = [Regex regexp:pattern]; 21 | [regExp enumerateMatchesInString:str 22 | options:NSMatchingReportCompletion 23 | range:range 24 | usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) { 25 | 26 | if (result){ 27 | if (result.numberOfRanges > capturingGroupIdx) 28 | { 29 | resultString = [Regex substring:str andRange: [result rangeAtIndex:capturingGroupIdx]]; 30 | } else { 31 | resultString = [Regex substring:str andRange:result.range]; 32 | } 33 | } 34 | }]; 35 | return resultString; 36 | } 37 | 38 | 39 | + (NSString*) firstMatchInString:(NSString*) str andPattern:(NSString*) pattern 40 | { 41 | NSRegularExpression* regExp = [Regex regexp:pattern]; 42 | NSTextCheckingResult* result = [regExp firstMatchInString:str options:NSMatchingReportCompletion range:NSMakeRange(0,str.length)]; 43 | 44 | if (result){ 45 | return [Regex substring:str andRange:result.range]; 46 | } 47 | 48 | return nil; 49 | } 50 | 51 | 52 | 53 | + (NSArray*) matchesInString:(NSString*) str andPattern:(NSString*) pattern 54 | { 55 | NSMutableArray* matches = [NSMutableArray new]; 56 | NSRegularExpression* regExp = [Regex regexp:pattern]; 57 | 58 | NSArray* results = [regExp matchesInString:str options:NSMatchingReportCompletion range:NSMakeRange(0,str.length)]; 59 | 60 | for (NSTextCheckingResult* result in results) { 61 | [matches addObject:[Regex substring:str andRange:result.range]]; 62 | } 63 | return matches; 64 | } 65 | 66 | 67 | // Private methods 68 | + (NSRegularExpression*) regexp:(NSString*) pattern 69 | { 70 | NSError* error = nil; 71 | NSRegularExpression* expression = [NSRegularExpression regularExpressionWithPattern:pattern 72 | options:NSRegularExpressionCaseInsensitive 73 | error:&error]; 74 | return expression; 75 | } 76 | 77 | + (NSString*) substring:(NSString*)str andRange:(NSRange) range 78 | { 79 | return [str substringWithRange:range]; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Categories/NSDictionary+Collection/NSDictionary+Collection.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+Collection.m 3 | // Collection 4 | // 5 | // Created by Jordi Puigdellívol on 10/8/16. 6 | // Copyright © 2016 Revo. All rights reserved. 7 | // 8 | 9 | #import "NSDictionary+Collection.h" 10 | #import "NSArray+Collection.h" 11 | 12 | @implementation NSDictionary (Collection) 13 | 14 | //=================================== 15 | #pragma mark - Converters 16 | //=================================== 17 | +(NSDictionary*)fromData:(NSData*)data{ 18 | if(!data) return nil; 19 | NSError* error; 20 | NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; 21 | return json; 22 | } 23 | 24 | +(NSDictionary*)fromString:(NSString*)string{ 25 | if( ! string || ! [string isKindOfClass:NSString.class]) return nil; 26 | NSData* data = [string dataUsingEncoding:NSUTF8StringEncoding]; 27 | return [self.class fromData:data]; 28 | } 29 | 30 | -(NSString*)toString{ 31 | NSError * err; 32 | NSData * jsonData = [NSJSONSerialization dataWithJSONObject:self options:NSJSONWritingPrettyPrinted error:&err]; 33 | return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 34 | } 35 | 36 | - (NSDictionary*)except:(NSArray*)exceptKeys{ 37 | NSMutableDictionary* result = self.mutableCopy; 38 | [exceptKeys each:^(NSString* key) { 39 | [result removeObjectForKey:key]; 40 | }]; 41 | return result; 42 | } 43 | 44 | - (NSDictionary*)only:(NSArray*)keysToKeep{ 45 | NSMutableDictionary* result = self.mutableCopy; 46 | [result.allKeys each:^(id key) { 47 | if( ! [keysToKeep containsObject:key] ) 48 | [result removeObjectForKey:key]; 49 | }]; 50 | return result; 51 | } 52 | 53 | //=================================== 54 | #pragma mark - Collection 55 | //=================================== 56 | - (void)each:(void(^)(id key, id object))operation{ 57 | 58 | [self enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { 59 | operation(key, obj); 60 | }]; 61 | } 62 | 63 | - (NSDictionary*)filter:(BOOL (^)(id key, id object))condition{ 64 | 65 | NSSet *keys = [self keysOfEntriesPassingTest:^BOOL(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { 66 | return condition(key,obj); 67 | }]; 68 | return [self dictionaryWithValuesForKeys:keys.allObjects]; 69 | } 70 | 71 | - (NSDictionary*)reject:(BOOL (^)(id key, id object))condition{ 72 | 73 | NSSet *keys = [self keysOfEntriesPassingTest:^BOOL(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { 74 | return ! condition(key,obj); 75 | }]; 76 | return [self dictionaryWithValuesForKeys:keys.allObjects]; 77 | } 78 | 79 | - (NSDictionary*)map:(id (^)(id key, id object))callback{ 80 | NSMutableDictionary* newDictionary = [NSMutableDictionary new]; 81 | [self each:^(id key, id object) { 82 | newDictionary[key] = callback(key,object); 83 | }]; 84 | return newDictionary; 85 | } 86 | @end 87 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Parsers/InequalityExtendedExpressionParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // InequalityExtendedExpressionParser.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 25/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "InequalityExtendedExpressionParser.h" 10 | #import "InequalityExtendedExpressionMatcher.h" 11 | 12 | @implementation InequalityExtendedExpressionParser 13 | 14 | 15 | - (id) parse 16 | { 17 | InequalitySignEnum firstSign = [self firstSign]; 18 | double firstValue = [self firstValue]; 19 | 20 | InequalitySignEnum secondSign = [self secondSign]; 21 | double secondValue = [self secondValue]; 22 | 23 | 24 | if (firstSign && firstValue && secondSign && secondValue){ 25 | 26 | if (firstValue < secondValue){ 27 | firstSign = [InequalitySignObject invertWithValue: firstSign]; 28 | } 29 | InequalityExpressionMatcher* leftMatcher = [[InequalityExpressionMatcher alloc] initWithInequalitySignEnum:firstSign withValue:firstValue]; 30 | InequalityExpressionMatcher* rightMatcher = [[InequalityExpressionMatcher alloc] initWithInequalitySignEnum:secondSign withValue:secondValue]; 31 | return [[InequalityExtendedExpressionMatcher alloc] initWithLeftMatcher:leftMatcher rightMatcher:rightMatcher]; 32 | } 33 | return nil; 34 | } 35 | 36 | 37 | #pragma mark - Private methods 38 | 39 | - (double) firstValue 40 | { 41 | NSString* regExpExpressionPatternTypeEnum = [ExpressionPatternTypeObject getStringFromExpressionPatternType:ExpressionPatternTypeEnum_InequalityExtended]; 42 | NSString* regExpSelf = @":(?<=^iex:)(-?\\d+[.]{0,1}[\\d]{0,})"; 43 | 44 | NSString* fullRegex = [NSString stringWithFormat:@"%@%@",regExpExpressionPatternTypeEnum,regExpSelf]; 45 | 46 | return [super getValueWithRegex:fullRegex withFailureMessage:@"Cannot find first value" withCapturingGroupIdx:1]; 47 | } 48 | 49 | - (double) secondValue 50 | { 51 | return [super getValueWithRegex:@"(?<=x<=|<)(-?\\d+[.]{0,1}[\\d]{0,})" withFailureMessage:@"Cannot find second value" withCapturingGroupIdx:1]; 52 | } 53 | 54 | - (InequalitySignEnum) firstSign 55 | { 56 | NSString* regExpExpressionPatternTypeEnum = [ExpressionPatternTypeObject getStringFromExpressionPatternType:ExpressionPatternTypeEnum_InequalityExtended]; 57 | NSString* regExpSelf = @":-?\\d{0,}[.]?\\d{0,}(<=|<|)"; 58 | NSString* fullRegex = [NSString stringWithFormat:@"%@%@",regExpExpressionPatternTypeEnum,regExpSelf]; 59 | 60 | return [super getSignWithRegex:fullRegex withFailureMessage:@"Cannot find first sign" withCapturingGroupIdx:1]; 61 | } 62 | 63 | 64 | - (InequalitySignEnum) secondSign 65 | { 66 | NSString* regExpExpressionPatternTypeEnum = [ExpressionPatternTypeObject getStringFromExpressionPatternType:ExpressionPatternTypeEnum_InequalityExtended]; 67 | NSString* regExpSelf = @":[-]?\\d*[.]?\\d*[<=>]{1,2}x(<=|<|)"; 68 | NSString* fullRegex = [NSString stringWithFormat:@"%@%@",regExpExpressionPatternTypeEnum,regExpSelf]; 69 | 70 | return [super getSignWithRegex:fullRegex withFailureMessage:@"Cannot find second sign" withCapturingGroupIdx:1]; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /Example/ObjCnalization.xcodeproj/xcshareddata/xcschemes/ObjCnalization-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 85 | 87 | 93 | 94 | 95 | 96 | 98 | 99 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Tests/Pods-ObjCnalization_Tests-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 104 | wait 105 | fi 106 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Example/Pods-ObjCnalization_Example-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | 104 | if [[ "$CONFIGURATION" == "Debug" ]]; then 105 | install_framework "${BUILT_PRODUCTS_DIR}/ObjCnalization/ObjCnalization.framework" 106 | fi 107 | if [[ "$CONFIGURATION" == "Release" ]]; then 108 | install_framework "${BUILT_PRODUCTS_DIR}/ObjCnalization/ObjCnalization.framework" 109 | fi 110 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 111 | wait 112 | fi 113 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Tests/Pods-ObjCnalization_Tests-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 53 | ;; 54 | *.xib) 55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync --delete -avr --copy-links --no-relative "${RSYNC_PROTECT_TMP_FILES[@]}" --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync --delete -avr --copy-links --no-relative "${RSYNC_PROTECT_TMP_FILES[@]}" --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-ObjCnalization_Example/Pods-ObjCnalization_Example-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 53 | ;; 54 | *.xib) 55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync --delete -avr --copy-links --no-relative "${RSYNC_PROTECT_TMP_FILES[@]}" --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync --delete -avr --copy-links --no-relative "${RSYNC_PROTECT_TMP_FILES[@]}" --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Translation(s)/LoadedTranslationsProcessor.m: -------------------------------------------------------------------------------- 1 | // 2 | // LoadedTranslationsProcessor.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 27/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "LoadedTranslationsProcessor.h" 10 | 11 | #import "Translation.h" 12 | #import "LoadedTranslation.h" 13 | #import "Regex.h" 14 | 15 | #import "NSArray+Collection.h" 16 | #import "NSArray+HighOrder.h" 17 | #import "Expression.h" 18 | #import "SharedExpression.h" 19 | #import "LengthVariation.h" 20 | 21 | @implementation LoadedTranslationsProcessor 22 | 23 | + (NSArray*) processTranslations:(NSArray*) baseTranslations 24 | andPreferedLanguageTranslations:(NSArray*) preferedLanguageTranslations 25 | andSharedExpressions:(NSArray*) sharedExpressions 26 | { 27 | NSMutableArray* uniqueBaseTranslations = [NSMutableArray arrayWithArray:baseTranslations]; 28 | 29 | if (preferedLanguageTranslations.count > 0) 30 | { 31 | uniqueBaseTranslations = (NSMutableArray*)[baseTranslations filter:^BOOL(LoadedTranslation* objectFirst) { 32 | 33 | return [[preferedLanguageTranslations filter:^BOOL(LoadedTranslation* objectSecond) { 34 | return [objectFirst.keyForDict isEqualToString:objectSecond.keyForDict]; 35 | }] count] == 0; 36 | }]; 37 | } 38 | 39 | NSArray* translationsReadyToProcess = [preferedLanguageTranslations arrayByAddingObjectsFromArray:uniqueBaseTranslations]; 40 | 41 | return [translationsReadyToProcess map:^id(id obj, NSUInteger idx) { 42 | 43 | LoadedTranslation* translation = (LoadedTranslation*)obj; 44 | 45 | switch(translation.typeEnum) { 46 | 47 | case LoadedTranslationTypeEnum_Simple: { 48 | NSString* value = translation.content[translation.keyForDict]; 49 | Expression* expr = [[Expression alloc]initWithPattern:translation.keyForDict andValue:value andLenghtVariations:nil]; 50 | return [[Translation alloc] initWithKey:translation.keyForDict andExpressions:@[expr]]; 51 | break; 52 | } 53 | 54 | case LoadedTranslationTypeEnum_WithExpressions: { 55 | 56 | NSMutableArray* expressions = [NSMutableArray new]; 57 | 58 | for (NSString* key in [translation.content allKeys]) { 59 | SharedExpression* firstObj = [[sharedExpressions filter:^BOOL(SharedExpression* sharedExpr) { 60 | return [sharedExpr.identifier isEqualToString:key]; 61 | }] firstObject]; 62 | 63 | NSString* pattern = (firstObj.pattern) ? firstObj.pattern : key; 64 | [expressions addObject: [[Expression alloc] initWithPattern:pattern andValue:translation.content[key] andLenghtVariations:nil]]; 65 | } 66 | return [[Translation alloc] initWithKey:translation.keyForDict andExpressions:expressions]; 67 | break; 68 | } 69 | 70 | case LoadedTranslationTypeEnum_WithLengthVariations: { 71 | 72 | NSMutableArray* lengthVariations = [NSMutableArray new]; 73 | for (NSString* key in [translation.content allKeys]) { 74 | 75 | LengthVariation* lenghVar = [[LengthVariation alloc] initWithWidth:[self parseNumberFromLengthVariation:key] 76 | strValue:translation.content[key]]; 77 | [lengthVariations addObject: lenghVar]; 78 | } 79 | 80 | Expression* expr = [[Expression alloc] initWithPattern:translation.keyForDict 81 | andValue: [lengthVariations lastObject].value 82 | andLenghtVariations:lengthVariations]; 83 | return [[Translation alloc] initWithKey:translation.keyForDict andExpressions:@[expr]]; 84 | break; 85 | } 86 | 87 | case LoadedTranslationTypeEnum_WithExpressionsAndLengthVariations: { 88 | 89 | NSMutableArray* expressions = [NSMutableArray new]; 90 | 91 | for (NSString* key in [translation.content allKeys]) 92 | { 93 | SharedExpression* firstObj = [[sharedExpressions filter:^BOOL(SharedExpression* sharedExpr) { 94 | return [sharedExpr.identifier isEqualToString:key]; 95 | }] firstObject]; 96 | 97 | NSString* pattern = (firstObj.pattern) ? firstObj.pattern : key; 98 | 99 | if([translation.content[key] isKindOfClass:[NSDictionary class]]) 100 | { 101 | NSMutableArray* lengthVariations = [NSMutableArray new]; 102 | 103 | [translation.content[key] enumerateKeysAndObjectsUsingBlock:^(id lvKey, id lvValue, BOOL *stop) { 104 | [lengthVariations addObject:[[LengthVariation alloc] initWithWidth:[LoadedTranslationsProcessor parseNumberFromLengthVariation:lvKey] 105 | strValue:lvValue]]; 106 | }]; 107 | 108 | [expressions addObject:[[Expression alloc]initWithPattern:pattern 109 | andValue:[lengthVariations lastObject].value 110 | andLenghtVariations:lengthVariations]]; 111 | 112 | } else if ([translation.content[key] isKindOfClass:[NSString class]]) 113 | { 114 | [expressions addObject: [[Expression alloc]initWithPattern:pattern andValue:translation.content[key] andLenghtVariations:nil]]; 115 | } 116 | } 117 | 118 | return [[Translation alloc] initWithKey:translation.keyForDict andExpressions:expressions]; 119 | break; 120 | } 121 | case LoadedTranslationTypeEnum_ErrorInitialization: { 122 | break; 123 | } 124 | } 125 | return @""; 126 | }]; 127 | } 128 | 129 | + (NSInteger) parseNumberFromLengthVariation:(NSString*) string 130 | { 131 | return [[Regex matchInString:string andPattern:@"@(\\d+)" andCapturingGroupIdx:1] integerValue]; 132 | } 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/ObjCnalization.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjCnalization.m 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | #import "ObjCnalization.h" 10 | #import "Translation.h" 11 | #import "JSONFileLoader.h" 12 | #import "SharedExpression.h" 13 | #import "SharedExpressionsLoader.h" 14 | 15 | #import "SharedExpressionsProcessor.h" 16 | #import "TranslationsLoader.h" 17 | #import "LoadedTranslationsProcessor.h" 18 | 19 | #import "NSArray+Collection.h" 20 | #import "NSArray+HighOrder.h" 21 | 22 | @implementation ObjCnalization 23 | 24 | + (instancetype)sharedInstance 25 | { 26 | static ObjCnalization *sharedMyManager = nil; 27 | static dispatch_once_t onceToken; 28 | dispatch_once(&onceToken, ^{ 29 | sharedMyManager = [[self alloc] init]; 30 | }); 31 | return sharedMyManager; 32 | } 33 | 34 | // This is short method of sharedInstance 35 | + (instancetype)call 36 | { 37 | return [ObjCnalization sharedInstance]; 38 | } 39 | 40 | #pragma mark - Public methods 41 | 42 | - (void) configure:(NSBundle*) bundle 43 | { 44 | if (bundle) 45 | [[ObjCnalization sharedInstance] load:bundle]; 46 | else 47 | [[ObjCnalization sharedInstance] load: [NSBundle mainBundle]]; 48 | 49 | } 50 | 51 | - (void) configureIfNeeded:(NSBundle*) bundle 52 | { 53 | if (!self.configured){ 54 | [[ObjCnalization sharedInstance] configure:bundle]; 55 | } 56 | } 57 | 58 | 59 | // Methods without pluralization 60 | - (NSString*) locStr:(NSString*) key 61 | { 62 | return [self localizedString:key andFittWidth:0 andDefaultVal:nil andComment:nil]; 63 | } 64 | 65 | 66 | - (NSString*) localizedString:(NSString*) key 67 | { 68 | return [self localizedString:key andFittWidth:0 andDefaultVal:nil andComment:nil]; 69 | } 70 | 71 | - (NSString*) localizedString:(NSString*) key 72 | andDefaultVal:(NSString*) defaultValue 73 | andComment:(NSString*) comment 74 | { 75 | return [self localizedString:key andFittWidth:0 andDefaultVal:defaultValue andComment:comment]; 76 | 77 | } 78 | 79 | 80 | - (NSString*) localizedString:(NSString*) key 81 | andFittWidth:(NSInteger) fittingWidth 82 | { 83 | return [self localizedString:key andFittWidth:fittingWidth andDefaultVal:nil andComment:nil]; 84 | } 85 | 86 | 87 | 88 | - (NSString*) localizedString:(NSString*) key 89 | andFittWidth:(NSInteger) fittingWidth 90 | andDefaultVal:(NSString*) defaultValue 91 | andComment:(NSString*) comment 92 | { 93 | return [self localizedString:key andStringVal:key andFittWidth:fittingWidth andDefaultVal:defaultValue andComment:comment]; 94 | } 95 | 96 | 97 | // String value methods 98 | 99 | - (NSString*) localizedString:(NSString*) key 100 | andStringVal:(NSString*) stringValue 101 | { 102 | return [self localizedString:key andStringVal:stringValue andFittWidth:0 andDefaultVal:nil andComment:nil]; 103 | } 104 | 105 | 106 | 107 | - (NSString*) localizedString:(NSString*) key 108 | andStringVal:(NSString*) stringValue 109 | andDefaultVal:(NSString*) defaultValue 110 | andComment:(NSString*) comment 111 | { 112 | return [self localizedString:key andStringVal:stringValue andFittWidth:0 andDefaultVal:defaultValue andComment:comment]; 113 | 114 | } 115 | 116 | 117 | - (NSString*) localizedString:(NSString*) key 118 | andStringVal:(NSString*) stringValue 119 | andFittWidth:(NSInteger) fittingWidth 120 | { 121 | return [self localizedString:key andStringVal:stringValue andFittWidth:fittingWidth andDefaultVal:nil andComment:nil]; 122 | } 123 | 124 | 125 | 126 | - (NSString*) localizedString:(NSString*) key 127 | andStringVal:(NSString*) stringValue 128 | andFittWidth:(NSInteger) fittingWidth 129 | andDefaultVal:(NSString*) defaultValue 130 | andComment:(NSString*) comment 131 | { 132 | [self configureIfNeeded:[NSBundle mainBundle]]; 133 | 134 | NSArray* filteredTranslations = [[ObjCnalization sharedInstance].translations filter:^BOOL(Translation* object) { 135 | return [object.key isEqualToString:key]; 136 | }]; 137 | 138 | Translation* translation = [filteredTranslations firstObject]; 139 | 140 | if (translation) 141 | { 142 | NSString* localizedValue = [translation validate:stringValue andFittingWidth:fittingWidth]; 143 | if (localizedValue) 144 | return localizedValue; 145 | } 146 | 147 | return (!defaultValue) ? defaultValue : key; 148 | } 149 | 150 | 151 | // Int value methods 152 | 153 | - (NSString*) localizedString:(NSString*) key 154 | andIntVal:(NSInteger) intValue 155 | { 156 | return [self localizedString:key andIntVal:intValue andFittWidth:0 andDefaultVal:nil andComment:nil]; 157 | 158 | } 159 | 160 | 161 | - (NSString*) localizedString:(NSString*) key 162 | andIntVal:(NSInteger) intValue 163 | andDefaultVal:(NSString*) defaultValue 164 | andComment:(NSString*) comment 165 | { 166 | return [self localizedString:key andIntVal:intValue andFittWidth:0 andDefaultVal:defaultValue andComment:comment]; 167 | } 168 | 169 | 170 | 171 | - (NSString*) localizedString:(NSString*) key 172 | andIntVal:(NSInteger) intValue 173 | andFittWidth:(NSInteger) fittingWidth; 174 | { 175 | return [self localizedString:key andIntVal:intValue andFittWidth:fittingWidth andDefaultVal:nil andComment:nil]; 176 | } 177 | 178 | - (NSString*) localizedString:(NSString*) key 179 | andIntVal:(NSInteger) intValue 180 | andFittWidth:(NSInteger) fittingWidth 181 | andDefaultVal:(NSString*) defaultValue 182 | andComment:(NSString*) comment 183 | { 184 | NSString* defValue = (defaultValue) ? defaultValue : [NSString stringWithFormat:@"defaultValue for =%@",key]; 185 | NSString* commentary = (comment) ? comment : [NSString stringWithFormat:@"comment for =%@",key]; 186 | 187 | return [self localizedString:key 188 | andStringVal:[NSString stringWithFormat:@"%ld",(long)intValue] 189 | andFittWidth:fittingWidth 190 | andDefaultVal:defValue 191 | andComment:commentary]; 192 | } 193 | 194 | 195 | 196 | #pragma mark - Private methods 197 | 198 | - (void) load:(NSBundle*) bundle 199 | { 200 | NSString* base = @"base"; 201 | NSString* language = [self getPreferredLanguage:[NSBundle mainBundle]]; 202 | 203 | NSArray* baseExpressions = [SharedExpressionsLoader loadExpressions: [JSONFileLoader loadExpressions:base andBundle:bundle]]; 204 | NSArray* languageExpressions = [SharedExpressionsLoader loadExpressions: [JSONFileLoader loadExpressions:language andBundle:bundle]]; 205 | 206 | NSArray* expressions = [SharedExpressionsProcessor processSharedExpression:language 207 | andPreferedLanguageExpressions:languageExpressions 208 | andBaseLanguageExpressions:baseExpressions]; 209 | 210 | NSArray* baseTranslations = [TranslationsLoader loadTranslations: [JSONFileLoader loadTranslations:base andBundle:bundle] ]; 211 | 212 | 213 | NSArray* languageTranslations = [TranslationsLoader loadTranslations: [JSONFileLoader loadTranslations:language andBundle:bundle] ]; 214 | 215 | NSArray* tmpTranslation = [LoadedTranslationsProcessor processTranslations:baseTranslations 216 | andPreferedLanguageTranslations:languageTranslations 217 | andSharedExpressions:expressions]; 218 | self.translations = [NSArray arrayWithArray:tmpTranslation]; 219 | self.configured = YES; 220 | 221 | } 222 | 223 | - (CountryCode*) getPreferredLanguage:(NSBundle*) bundle 224 | { 225 | CountryCode* code = [bundle.preferredLocalizations firstObject]; 226 | if (code){ 227 | return code; 228 | } 229 | return @"Not found region`s code"; 230 | } 231 | 232 | @end 233 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/ObjCnalization.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjCnalization.h 3 | // ObjCnalization 4 | // 5 | // Created by Uber on 26/11/2017. 6 | // Copyright © 2017 Uber. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | 12 | typedef NSString CountryCode; 13 | @class Translation; 14 | 15 | 16 | @interface ObjCnalization : NSObject 17 | 18 | + (instancetype)sharedInstance; 19 | + (instancetype)call; // short method of sharedInstance 20 | 21 | @property (nonatomic, strong) NSArray* translations; 22 | @property (nonatomic, assign) BOOL configured; 23 | 24 | #pragma mark - Public methods 25 | 26 | - (void) configure:(NSBundle*) bundle; 27 | 28 | - (void) configureIfNeeded:(NSBundle*) bundle; 29 | 30 | 31 | /** 32 | Get localized value for a (key). 33 | 34 | :param: key - to which localized string is assigned. 35 | :returns: localized value. 36 | */ 37 | // Short syntax 38 | - (NSString*) locStr:(NSString*) key; 39 | 40 | /** 41 | Get localized value for a (key). 42 | 43 | :param: key - to which localized string is assigned. 44 | :returns: localized value. 45 | */ 46 | 47 | // Full syntax 48 | - (NSString*) localizedString:(NSString*) key; 49 | 50 | 51 | /** 52 | Get localized value for a (key/defaultValue/comment). 53 | 54 | :param: key - to which localized string is assigned. 55 | :param: defaultValue - the default value which will return method in case of failure 56 | :param: comment - about the key and localized value. Just for developer use for describing key-value pair. 57 | :returns: localized value. 58 | */ 59 | 60 | - (NSString*) localizedString:(NSString*) key 61 | andDefaultVal:(NSString*) defaultValue 62 | andComment:(NSString*) comment; 63 | 64 | 65 | /** 66 | Get localized value for a (key/fittingWidth). 67 | 68 | :param: key - to which localized string is assigned. 69 | :param: fittingWidth - max width that value should fit to. If there is no 70 | value specified the full-length localized string is returned. If a 71 | passed fitting width is greater than highest available then a value for 72 | highest available width is returned. 73 | :returns: localized value. 74 | */ 75 | - (NSString*) localizedString:(NSString*) key 76 | andFittWidth:(NSInteger) fittingWidth; 77 | 78 | 79 | 80 | /** 81 | Get localized value for a (key/fittingWidth/defaultValue/comment) 82 | 83 | :param: key - to which localized string is assigned. 84 | :param: fittingWidth - max width that value should fit to. If there is no 85 | value specified the full-length localized string is returned. If a 86 | passed fitting width is greater than highest available then a value for 87 | highest available width is returned. 88 | 89 | :param: defaultValue - the default value which will return method in case of failure 90 | :param: comment - about the key and localized value. Just for developer use for describing key-value pair. 91 | :returns: localized value. 92 | */ 93 | - (NSString*) localizedString:(NSString*) key 94 | andFittWidth:(NSInteger) fittingWidth 95 | andDefaultVal:(NSString*) defaultValue 96 | andComment:(NSString*) comment; 97 | 98 | /** 99 | Get localized value for a (key/stringValue) 100 | 101 | :param: key - to which localized string is assigned. 102 | :param: stringValue - value that is matched by expression 103 | :returns: localized value. 104 | */ 105 | - (NSString*) localizedString:(NSString*) key 106 | andStringVal:(NSString*) stringValue; 107 | 108 | 109 | /** 110 | Get localized value for a (key/stringValue) 111 | 112 | :param: key - to which localized string is assigned. 113 | :param: stringValue - value that is matched by expression 114 | :param: defaultValue - the default value which will return method in case of failure 115 | :param: comment - about the key and localized value. Just for developer use for describing key-value pair. 116 | :returns: localized value. 117 | */ 118 | 119 | - (NSString*) localizedString:(NSString*) key 120 | andStringVal:(NSString*) stringValue 121 | andDefaultVal:(NSString*) defaultValue 122 | andComment:(NSString*) comment; 123 | 124 | 125 | /** 126 | Get localized value for a (key / stringValue / fittingWidth). 127 | 128 | :param: key - to which localized string is assigned. 129 | :param: stringValue - value that is matched by expression. 130 | :param: fittingWidth - max width that value should fit to. 131 | 132 | :returns: localized value. 133 | */ 134 | - (NSString*) localizedString:(NSString*) key 135 | andStringVal:(NSString*) stringValue 136 | andFittWidth:(NSInteger) fittingWidth; 137 | 138 | 139 | /** 140 | Get localized value for a (key / stringValue / fittingWidth / defaultValue / comment). 141 | 142 | :param: key - to which localized string is assigned. 143 | :param: stringValue - value that is matched by expression. 144 | :param: fittingWidth - max width that value should fit to. 145 | :param: defaultValue - the default value which will return method in case of failure 146 | :param: comment - about the key and localized value. Just for developer use for describing key-value pair. 147 | :returns: localized value. 148 | */ 149 | 150 | - (NSString*) localizedString:(NSString*) key 151 | andStringVal:(NSString*) stringValue 152 | andFittWidth:(NSInteger) fittingWidth 153 | andDefaultVal:(NSString*) defaultValue 154 | andComment:(NSString*) comment; 155 | 156 | //------------------------------------------------------// 157 | 158 | 159 | 160 | /** 161 | Get localized value for a (key / intValue). 162 | 163 | :param: key - to which localized string is assigned. 164 | :param: intValue - value that is matched by expression. 165 | :returns: localized value. 166 | */ 167 | - (NSString*) localizedString:(NSString*) key 168 | andIntVal:(NSInteger) intValue; 169 | 170 | 171 | /** 172 | Get localized value for a (key / intValue / defaultValue / comment). 173 | 174 | :param: key - to which localized string is assigned. 175 | :param: intValue - value that is matched by expression. 176 | :param: defaultValue - the default value which will return method in case of failure 177 | :param: comment - about the key and localized value. Just for developer use for describing key-value pair. 178 | :returns: localized value. 179 | */ 180 | - (NSString*) localizedString:(NSString*) key 181 | andIntVal:(NSInteger) intValue 182 | andDefaultVal:(NSString*) defaultValue 183 | andComment:(NSString*) comment; 184 | 185 | 186 | 187 | /** 188 | Get localized value for a (key / intValue / fittingWidth). 189 | 190 | :param: key - to which localized string is assigned. 191 | :param: intValue - value that is matched by expression. 192 | :param: fittingWidth - max width that value should fit to. 193 | 194 | :returns: localized value. 195 | */ 196 | - (NSString*) localizedString:(NSString*) key 197 | andIntVal:(NSInteger) intValue 198 | andFittWidth:(NSInteger) fittingWidth; 199 | 200 | 201 | /** 202 | Get localized value for a (key / intValue / fittingWidth). 203 | 204 | :param: key - to which localized string is assigned. 205 | :param: intValue - value that is matched by expression. 206 | :param: fittingWidth - max width that value should fit to. 207 | :param: defaultValue - the default value which will return method in case of failure 208 | :param: comment - about the key and localized value. Just for developer use for describing key-value pair. 209 | :returns: localized value. 210 | */ 211 | - (NSString*) localizedString:(NSString*) key 212 | andIntVal:(NSInteger) intValue 213 | andFittWidth:(NSInteger) fittingWidth 214 | andDefaultVal:(NSString*) defaultValue 215 | andComment:(NSString*) comment; 216 | 217 | 218 | //------------------------------------------------------// 219 | 220 | 221 | #pragma mark - Private methods 222 | 223 | - (void) load:(NSBundle*) bundle; 224 | - (CountryCode*) getPreferredLanguage:(NSBundle*) bundle; 225 | 226 | @end 227 | 228 | typedef ObjCnalization I18n; 229 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Categories/NSArray+Collection/NSArray+Collection.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Collection.h 3 | // revo-retail 4 | // 5 | // Created by Badchoice on 25/5/16. 6 | // Copyright © 2016 Revo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSArray (Collection) 12 | 13 | /** 14 | * @return NSArray with only the elements that pass the truth test 15 | */ 16 | - (NSArray*)filter:(BOOL (^)(id object))condition; 17 | 18 | /** 19 | * @return NSArray with only the elements that keypath is true 20 | */ 21 | - (NSArray*)filterWith:(NSString*)keypath; 22 | 23 | /** 24 | * @return NSArray removing the elements that pass the truth test 25 | */ 26 | - (NSArray*)reject:(BOOL (^)(id object))condition; 27 | 28 | /** 29 | * @return NSArray without the elements that keypath is true 30 | */ 31 | - (NSArray*)rejectWith:(NSString*)keypath; 32 | 33 | /** 34 | * @return id first object that passes the truth test or `nil` if any 35 | */ 36 | - (id)first:(BOOL (^)(id object))condition; 37 | 38 | /** 39 | * @return id first object that passes the truth test or `defaultObject` if any passes 40 | */ 41 | - (id)first:(BOOL (^)(id object))condition default:(id)defaultObject; 42 | 43 | /** 44 | * @return id last object that passes the truth test or `nil` if any 45 | */ 46 | - (id)last:(BOOL (^)(id))condition; 47 | 48 | /** 49 | * @return id last object that passes the truth test or `defaultObject` if any passes 50 | */ 51 | - (id)last:(BOOL (^)(id object))condition default:(id)defaultObject; 52 | 53 | /** 54 | * @return BOOL if any object passes the truth test 55 | */ 56 | - (BOOL)contains:(BOOL (^)(id object))checker; 57 | 58 | /** 59 | * @return BOOL if no object passes the truth test 60 | */ 61 | - (BOOL)doesntContain:(BOOL (^)(id object))checker; 62 | 63 | /** 64 | * @return NSArray elements where the keypath contains the value 65 | */ 66 | - (NSArray*)where:(NSString*)keypath like:(id)value; 67 | 68 | /** 69 | * @return NSArray elements where the keypath is equal to the value 70 | */ 71 | - (NSArray*)where:(NSString*)keypath is:(id)value; 72 | 73 | /** 74 | * @return NSArray elements where any of the keypaths is equal to the value 75 | */ 76 | - (NSArray*)whereAny:(NSArray*)keyPaths is:(id)value; 77 | 78 | /** 79 | * @return NSArray elements where any of the keypaths is like the value 80 | */ 81 | - (NSArray*)whereAny:(NSArray*)keyPaths like:(id)value; 82 | 83 | 84 | /** 85 | * performs the operation to each element 86 | */ 87 | - (void)each:(void(^)(id object))operation; 88 | 89 | /** 90 | * performs the operation to each element 91 | */ 92 | - (void)eachWithIndex:(void(^)(id object, int index, BOOL *stop))operation; 93 | 94 | 95 | /** 96 | * @return NSArray sorted using `compare` function of the elements 97 | */ 98 | - (NSArray*)sort; 99 | 100 | /** 101 | * @return NSArray sorted ascending by the key values 102 | */ 103 | - (NSArray*)sort:(NSString*)key; 104 | 105 | /** 106 | * @return NSArray sorted by the key values 107 | */ 108 | - (NSArray*)sort:(NSString*)key ascending:(BOOL)ascending; 109 | 110 | /** 111 | * @return NSArray sorted using custom callback 112 | */ 113 | - (NSArray*)sortWith:(NSComparisonResult (^)(id a, id b))callback; 114 | 115 | 116 | /** 117 | * @return NSArray reverted 118 | */ 119 | - (NSArray*)reverse; 120 | 121 | /** 122 | * @return NSArray starting at howMany position 123 | */ 124 | - (NSArray*)slice :(int)howMany; 125 | 126 | /** 127 | * @return NSArray from [0 , howMany], if howMany is negative it returns [count - howMany , count] 128 | */ 129 | - (NSArray*)take :(int)howMany; 130 | 131 | /** 132 | * @return NSArray from [0 , howMany] and removes them from current array 133 | */ 134 | - (NSArray*)splice :(int)howMany; 135 | 136 | /** 137 | * @return new NSArray from the result of the block performed to each element 138 | */ 139 | - (NSArray*)map:(id (^)(id obj, NSUInteger idx))block; 140 | 141 | /** 142 | * @return new NSArray by flatting it and performing a map to each element 143 | */ 144 | - (NSArray*)flatMap:(id (^)(id obj, NSUInteger idx))block; 145 | 146 | /** 147 | * @return new NSArray by flatting it with the key and performing a map to each element 148 | */ 149 | - (NSArray*)flatMap:(NSString*)key block:(id (^)(id obj, NSUInteger idx))block; 150 | 151 | /** 152 | * @return NSArray of all element.keyPath 153 | */ 154 | - (NSArray*)pluck:(NSString*)keyPath; 155 | 156 | /** 157 | * @return NSDictionary of all element.keyPath with the key 158 | */ 159 | - (NSDictionary*)pluck:(NSString*)keyPath key:(NSString*)keyKeypath; 160 | 161 | /** 162 | * @return NSArray removes one level of arrays so [[1,2,3],[4,5,6]] becomes [1,2,3,4,5,6] 163 | */ 164 | - (NSArray*)flatten; 165 | 166 | /** 167 | * @return NSArray removes one level with key so [{"hola" => [1,2]},{"hola"=>[3,4]}] becomes [1,2,3,4] 168 | */ 169 | - (NSArray*)flatten:(NSString*)keypath; 170 | 171 | /** 172 | * @return reduces the array to a single value, passing the result of each iteration into the subsequent iteration 173 | * initial carry value is `nil` 174 | */ 175 | - (id)reduce:(id(^)(id carry, id object))block; 176 | 177 | /** 178 | * @return reduces the array to a single value, passing the result of each iteration into the subsequent iteration 179 | * initial carry value is `carry` 180 | */ 181 | - (id)reduce:(id(^)(id carry, id object))block carry:(id)carry; 182 | 183 | /** 184 | * Final collection is run through the transformer 185 | * and then the output of that is returned 186 | */ 187 | - (id)pipe:(id (^)(NSArray* array))block; 188 | 189 | /** 190 | * If condition is true, the collection is run throught block and is result is returned 191 | * if condition is false, it is ignored, and self is returned 192 | */ 193 | - (id)when:(BOOL)condition block:(id (^)(NSArray* array))block; 194 | 195 | /** 196 | * returns NSDictionary by grouping the array items by a given key: 197 | */ 198 | - (NSDictionary*)groupBy:(NSString*)keypath; 199 | 200 | /** 201 | * returns NSDictionary by grouping the array items by a given key where the new diciontary key is the result of block: 202 | */ 203 | - (NSDictionary*)groupBy:(NSString*)keypath block:(NSString*(^)(id object, NSString* key))block; 204 | 205 | /** 206 | * return NSDictionary copping to keypath all the elements of the keypath so 207 | * [ 208 | * {"groups" => [1,2] }, 209 | * {"groups" => [2,3,3] } 210 | * ] 211 | * becomes 212 | * { 213 | * 1 => [ 214 | * {"groups" => [1,2]} 215 | * ] 216 | * 2 => [ 217 | * {"groups" => [1,2]}, 218 | * {"groups" => [2,3,3]} 219 | * ] 220 | * 3 => [ 221 | * {"groups" => [2,3,3]} 222 | * {"groups" => [2,3,3]} 223 | * ] 224 | * } 225 | */ 226 | - (NSDictionary*)expand:(NSString*)keypath; 227 | 228 | /** 229 | * return same as expand but with uniques test so dictionary doesn't have duplicated values 230 | */ 231 | - (NSDictionary*)expand:(NSString *)keypath unique:(BOOL)unique; 232 | 233 | /** 234 | * Returns the greatests element in the array 235 | */ 236 | -(id)maxObject; 237 | 238 | /** 239 | * Returns the greatests element.keypath in the array 240 | */ 241 | -(id)maxObject:(NSString*)keypath; 242 | 243 | /** 244 | * Returns the minimum block(element) in the array 245 | */ 246 | -(id)maxObjectFor:(double(^)(id obj))block; 247 | 248 | /** 249 | * Returns the greatests element in the array 250 | */ 251 | -(id)minObject; 252 | 253 | /** 254 | * Returns the minimum element.keypath in the array 255 | */ 256 | -(id)minObject:(NSString*)keypath; 257 | 258 | /** 259 | * Returns the minimum block(element) in the array 260 | */ 261 | -(id)minObjectFor:(double(^)(id obj))block; 262 | 263 | /** 264 | * Returns a random object from within the array 265 | */ 266 | -(id)random; 267 | 268 | /** 269 | * Returns an array of `quantity` number of object from the array 270 | */ 271 | -(NSArray*)random:(int)quantity; 272 | 273 | /** 274 | * Returns the same array with the items sorted randomly 275 | */ 276 | -(NSArray*)shuffled; 277 | 278 | /** 279 | * Returns an array of all permutations 280 | */ 281 | -(NSArray*)permutations; 282 | 283 | /** 284 | *zip lets you take one collection, and pair every element in that collection with the 285 | *corresponding element in another collection.*/ 286 | -(NSArray*)zip:(NSArray*)other; 287 | 288 | /** 289 | * Associates 290 | */ 291 | -(NSDictionary*)mapToAssoc:(NSArray*(^)(id obj, NSUInteger idx))block; 292 | 293 | /** 294 | * Convenience method for creating the counted set 295 | */ 296 | -(NSCountedSet*)countedSet; 297 | 298 | /** 299 | * Returns an string concatedated with delimiter 300 | */ 301 | -(NSString*)implode:(NSString*)delimiter; 302 | 303 | /** 304 | * Converts the array into json string 305 | * of type [1,2,3] 306 | */ 307 | -(NSString*)toString; 308 | 309 | /** 310 | * Converts the array to json string 311 | */ 312 | -(NSString*)toJson; 313 | 314 | #pragma mark - Operators 315 | - (NSArray*)intersect:(NSArray*)b; 316 | - (NSArray*)union:(NSArray*)b; 317 | - (NSArray*)join:(NSArray*)b; 318 | - (NSArray*)diff:(NSArray*)b; 319 | - (NSArray*)minus:(NSArray*)b; 320 | - (NSArray*)distinct; 321 | - (NSArray*)distinct:(NSString*)keypath; 322 | 323 | /** 324 | * Returns all the combinations with all array items 325 | */ 326 | - (NSArray*)crossJoin:(NSArray*)list; 327 | + (NSArray*)cartesianProduct:(NSArray*)arrays; //used by the cross join 328 | 329 | #pragma mark - Set Operators 330 | - (NSNumber*)sum; 331 | - (NSNumber*)sum:(NSString*)keypath; 332 | - (NSNumber*)sumWith:(NSNumber*(^)(id object))block; 333 | - (NSNumber*)avg; 334 | - (NSNumber*)avg:(NSString*)keypath; 335 | - (NSNumber*)max; 336 | - (NSNumber*)max:(NSString*)keypath; 337 | - (NSNumber*)min; 338 | - (NSNumber*)min:(NSString*)keypath; 339 | 340 | 341 | @end 342 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Categories/NSString+Collection/NSString+Collection.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Collection.m 3 | // Collection 4 | // 5 | // Created by Jordi Puigdellívol on 10/8/16. 6 | // Copyright © 2016 Revo. All rights reserved. 7 | // 8 | 9 | #import "NSString+Collection.h" 10 | #import "NSArray+Collection.h" 11 | #import 12 | 13 | #define str(A,...) [NSString stringWithFormat:A,##__VA_ARGS__] 14 | 15 | @implementation NSString (Collection) 16 | 17 | 18 | +(NSString*)repeat:(NSString*)text times:(int)times{ 19 | if(times <= 0) return @""; 20 | NSMutableString* str = [NSMutableString string]; 21 | for(int i = 0; i < times; i++){ 22 | [str appendString:text]; 23 | } 24 | return str; 25 | } 26 | 27 | +(BOOL)isEmptyString:(NSString*)string{ 28 | if(string == nil) return true; 29 | if([string isKindOfClass:NSNull.class]) return true; 30 | if([string isEqualToString:@""]) return true; 31 | return false; 32 | } 33 | 34 | -(NSArray*)explode:(NSString*)delimiter{ 35 | return [self componentsSeparatedByString:delimiter]; 36 | } 37 | 38 | - (NSString*)initials{ 39 | NSArray* components = [self explode:@" "]; 40 | 41 | if(components.count == 1) return [self substringToIndex:MIN(3,self.length)]; 42 | 43 | return [[components take:3] reduce:^id(NSString* carry, NSString* component) { 44 | return [carry stringByAppendingString:[component substringToIndex:1]]; 45 | } carry:@""]; 46 | } 47 | 48 | -(NSNumber*)toNumber{ 49 | return @([self stringByReplacingOccurrencesOfString:@"," withString:@"."].floatValue); 50 | } 51 | 52 | -(NSString*)append:(NSString*)append{ 53 | return [self stringByAppendingString:append]; 54 | } 55 | 56 | -(NSString*)prepend:(NSString*)prepend{ 57 | return [prepend stringByAppendingString:self]; 58 | } 59 | 60 | -(NSString*) substr:(int)from{ 61 | if(from >=0) return [self substringFromIndex:MIN(from,(int)self.length)]; 62 | else return [self substringFromIndex:MAX((int)self.length + from, 0 )]; 63 | } 64 | 65 | -(NSString*)substr:(int)from length:(int)length{ 66 | if(from >=0){ 67 | return [self substringWithRange:NSMakeRange(from, MIN(length,self.length))]; 68 | } 69 | else{ 70 | return [self substringWithRange:NSMakeRange(self.length + from,length)]; 71 | } 72 | } 73 | 74 | -(NSString*)trim{ 75 | return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 76 | } 77 | 78 | -(NSString*)trimWithNewLine{ 79 | return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 80 | } 81 | 82 | -(NSString*)replace:(NSString*)character with:(NSString*)replace{ 83 | return [self stringByReplacingOccurrencesOfString:character withString:replace]; 84 | } 85 | 86 | - (NSArray*) split{ 87 | return [self split:1]; 88 | } 89 | 90 | - (NSArray*) split:(int)splitLength{ 91 | NSMutableArray *array = [NSMutableArray array]; 92 | for (int i = 0; i < self.length; i = i+splitLength) { 93 | [array addObject: [self substr:i length:(int)MIN(splitLength, self.length - i)]]; 94 | } 95 | return array; 96 | } 97 | 98 | 99 | 100 | - (NSString *)trimLeft{ 101 | NSCharacterSet *characterSet = [NSCharacterSet whitespaceCharacterSet]; 102 | NSUInteger location = 0; 103 | NSUInteger length = [self length]; 104 | unichar charBuffer[length]; 105 | [self getCharacters:charBuffer]; 106 | 107 | for (location = 0; location < length; location++) { 108 | if (![characterSet characterIsMember:charBuffer[location]]) { 109 | break; 110 | } 111 | } 112 | 113 | return [self substringWithRange:NSMakeRange(location, length - location)]; 114 | } 115 | 116 | - (NSString *)trimRight{ 117 | NSCharacterSet *characterSet = [NSCharacterSet whitespaceCharacterSet]; 118 | NSUInteger location = 0; 119 | NSUInteger length = 0; 120 | unichar charBuffer[length]; 121 | [self getCharacters:charBuffer]; 122 | 123 | for (length = self.length; length > 0; length--) { 124 | if (![characterSet characterIsMember:charBuffer[length - 1]]) { 125 | break; 126 | } 127 | } 128 | 129 | return [self substringWithRange:NSMakeRange(location, length - location)]; 130 | } 131 | 132 | - (NSString *)camelCase{ 133 | return self.pascalCase.lcFirst; 134 | } 135 | 136 | - (NSString *)pascalCase{ 137 | NSString* withoutWhiteSpaces = [[self explode:@" "] reduce:^id(NSString* carry, NSString* word) { 138 | return str(@"%@%@",carry,word.ucFirst); 139 | } carry:@""]; 140 | 141 | return [[withoutWhiteSpaces explode:@"_"] reduce:^id(NSString* carry, NSString* word) { 142 | return str(@"%@%@",carry,word.ucFirst); 143 | } carry:@""]; 144 | } 145 | 146 | -(NSString *)snakeCase{ 147 | NSUInteger index = 1; 148 | NSMutableString *snakeCaseString = [NSMutableString stringWithString:self]; 149 | NSUInteger length = snakeCaseString.length; 150 | NSMutableCharacterSet *characterSet = [NSCharacterSet uppercaseLetterCharacterSet].mutableCopy; 151 | [characterSet formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]]; 152 | while (index < length) { 153 | if ([characterSet characterIsMember:[snakeCaseString characterAtIndex:index]]) { 154 | [snakeCaseString insertString:@"_" atIndex:index]; 155 | index++; 156 | } 157 | index++; 158 | } 159 | return [snakeCaseString.lowercaseString replace:@" " with:@""]; 160 | } 161 | 162 | - (NSString *)ucFirst { 163 | if (self.length <= 1) { 164 | return self.uppercaseString; 165 | } else { 166 | return str(@"%@%@",[[self substringToIndex:1] uppercaseString], 167 | [self substringFromIndex:1]); 168 | } 169 | } 170 | 171 | - (NSString *)lcFirst { 172 | if (self.length <= 1) { 173 | return self.lowercaseString; 174 | } else { 175 | return str(@"%@%@",[[self substringToIndex:1] lowercaseString], 176 | [self substringFromIndex:1]); 177 | } 178 | } 179 | 180 | - (NSString*)withoutDiacritic{ 181 | return [self stringByFoldingWithOptions:NSDiacriticInsensitiveSearch 182 | locale:[NSLocale systemLocale]]; 183 | } 184 | 185 | -(BOOL)endsWith:(NSString *)compare{ 186 | NSPredicate *fltr = [NSPredicate predicateWithFormat:@"self ENDSWITH %@",compare]; 187 | return [fltr evaluateWithObject:self]; 188 | } 189 | 190 | -(BOOL)startsWith:(NSString *)compare{ 191 | //[c] for case insensitive 192 | //NSPredicate *fltr = [NSPredicate predicateWithFormat:@"self BEGINSWITH[c] %@",compare]; 193 | NSPredicate *fltr = [NSPredicate predicateWithFormat:@"self BEGINSWITH %@",compare]; 194 | return [fltr evaluateWithObject:self]; 195 | } 196 | 197 | -(BOOL)contains:(NSString *)compare{ 198 | //[c] for case insensitive 199 | //NSPredicate *fltr = [NSPredicate predicateWithFormat:@"self BEGINSWITH[c] %@",compare]; 200 | NSPredicate *fltr = [NSPredicate predicateWithFormat:@"self CONTAINS %@",compare]; 201 | return [fltr evaluateWithObject:self]; 202 | } 203 | 204 | -(BOOL)matches:(NSString*)regexp{ 205 | NSPredicate *regexpTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regexp]; 206 | return ([regexpTest evaluateWithObject: self]); 207 | } 208 | 209 | -(NSString*)lpad:(int)lenght string:(NSString*)string{ 210 | int finalLength = MAX(0, lenght - (int)self.length); 211 | NSString* padChars = [[NSString string] stringByPaddingToLength:finalLength 212 | withString:string 213 | startingAtIndex:0]; 214 | 215 | return [padChars append:self]; 216 | 217 | } 218 | 219 | -(NSString*)rpad:(int)lenght string:(NSString*)string{ 220 | return [self stringByPaddingToLength:MAX((int)self.length,lenght) 221 | withString:string 222 | startingAtIndex:0]; 223 | } 224 | 225 | -(NSString*)urlEncode{ 226 | return [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]]; 227 | } 228 | 229 | -(NSString*)urlDecode{ 230 | return [self stringByRemovingPercentEncoding]; 231 | } 232 | 233 | -(NSString*)md5{ 234 | const char *cStr = [self UTF8String]; 235 | unsigned char digest[16]; 236 | 237 | CC_MD5(cStr, (CC_LONG)strlen(cStr), digest); 238 | 239 | NSMutableString *md5 = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; 240 | 241 | for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { 242 | [md5 appendFormat:@"%02x", digest[i]]; 243 | } 244 | return md5; 245 | } 246 | 247 | -(NSString*)toBase64{ 248 | NSData *plainData = [self dataUsingEncoding:NSUTF8StringEncoding]; 249 | return [plainData base64EncodedStringWithOptions:kNilOptions]; 250 | } 251 | 252 | +(NSString*)fromBase64:(NSString*)base64{ 253 | return base64; //TODO 254 | } 255 | 256 | + (NSString *) fromHex:(NSString *)str 257 | { 258 | NSMutableData *stringData = [[NSMutableData alloc] init]; 259 | unsigned char whole_byte; 260 | char byte_chars[3] = {'\0','\0','\0'}; 261 | int i; 262 | for (i=0; i < [str length] / 2; i++) { 263 | byte_chars[0] = [str characterAtIndex:i*2]; 264 | byte_chars[1] = [str characterAtIndex:i*2+1]; 265 | whole_byte = strtol(byte_chars, NULL, 16); 266 | [stringData appendBytes:&whole_byte length:1]; 267 | } 268 | 269 | return [[NSString alloc] initWithData:stringData encoding:NSASCIIStringEncoding]; 270 | } 271 | 272 | - (NSString *) toHex 273 | { 274 | NSUInteger len = self.length; 275 | unichar *chars = malloc(len * sizeof(unichar)); 276 | [self getCharacters:chars]; 277 | 278 | NSMutableString *hexString = [[NSMutableString alloc] init]; 279 | 280 | for(NSUInteger i = 0; i < len; i++ ) 281 | { 282 | [hexString appendString:[NSString stringWithFormat:@"%x", chars[i]]]; 283 | } 284 | free(chars); 285 | 286 | return hexString; 287 | } 288 | 289 | 290 | @end 291 | -------------------------------------------------------------------------------- /Example/ObjCnalization/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | AvenirNext-Regular 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 38 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 84 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /ObjCnalization/Classes/Categories/NSArray+Collection/NSArray+Collection.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Collection.m 3 | // revo-retail 4 | // 5 | // Created by Badchoice on 25/5/16. 6 | // Copyright © 2016 Revo. All rights reserved. 7 | // 8 | 9 | #import "NSArray+Collection.h" 10 | #import "NSString+Collection.h" 11 | 12 | @implementation NSArray (Collection) 13 | 14 | - (NSArray*)filter:(BOOL (^)(id object))condition{ 15 | return [self filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary * _Nullable bindings) { 16 | return condition(evaluatedObject); 17 | }]]; 18 | } 19 | 20 | - (NSArray*)reject:(BOOL (^)(id object))condition{ 21 | return [self filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary * _Nullable bindings) { 22 | return !condition(evaluatedObject); 23 | }]]; 24 | } 25 | 26 | -(NSArray*)filterWith:(NSString *)keypath{ 27 | return [self filter:^BOOL(id object) { 28 | return [[object valueForKeyPath:keypath] boolValue]; 29 | }]; 30 | } 31 | 32 | -(NSArray*)rejectWith:(NSString *)keypath{ 33 | return [self reject:^BOOL(id object) { 34 | return [[object valueForKeyPath:keypath] boolValue]; 35 | }]; 36 | } 37 | 38 | - (id)first:(BOOL (^)(id object))condition{ 39 | NSUInteger index = [self indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 40 | return condition(obj); 41 | }]; 42 | 43 | return (index == NSNotFound) ? nil : self[index]; 44 | } 45 | 46 | - (id)first:(BOOL (^)(id object))condition default:(id)defaultObject{ 47 | id object = [self first:condition]; 48 | return (object) ? object : defaultObject; 49 | } 50 | 51 | - (id)last:(BOOL (^)(id))condition{ 52 | return [self.reverse first:condition]; 53 | } 54 | 55 | - (id)last:(BOOL (^)(id object))condition default:(id)defaultObject{ 56 | id object = [self last:condition]; 57 | return (object) ? object : defaultObject; 58 | } 59 | 60 | -(BOOL)contains:(BOOL (^)(id object))checker{ 61 | bool __block found = false; 62 | [self eachWithIndex:^(id object, int index, BOOL *stop) { 63 | if (checker(object)){ 64 | found = true; 65 | *stop = true; 66 | } 67 | }]; 68 | return found; 69 | } 70 | 71 | -(BOOL)doesntContain:(BOOL (^)(id object))checker{ 72 | bool __block found = false; 73 | [self eachWithIndex:^(id object, int index, BOOL *stop) { 74 | if (checker(object)){ 75 | found = true; 76 | *stop = true; 77 | } 78 | }]; 79 | return ! found; 80 | } 81 | 82 | - (NSArray*)where:(NSString*)keypath like:(id)value{ 83 | return [self whereAny:@[keypath] like:value]; 84 | } 85 | 86 | - (NSArray*)where:(NSString*)keypath is:(id)value{ 87 | return [self whereAny:@[keypath] is:value]; 88 | } 89 | 90 | - (NSArray*)whereAny:(NSArray*)keyPaths is:(id)value{ 91 | NSMutableArray* predicates = [NSMutableArray new]; 92 | 93 | [keyPaths each:^(NSString* keypath) { 94 | NSPredicate* predicate = [NSPredicate predicateWithFormat:@"%K = %@",keypath,value]; 95 | [predicates addObject:predicate]; 96 | }]; 97 | 98 | NSPredicate *resultPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicates]; 99 | return [self filteredArrayUsingPredicate:resultPredicate]; 100 | } 101 | 102 | - (NSArray*)whereAny:(NSArray*)keyPaths like:(id)value{ 103 | NSMutableArray* predicates = [NSMutableArray new]; 104 | 105 | [keyPaths each:^(NSString* keypath) { 106 | NSPredicate* predicate = [NSPredicate predicateWithFormat:@"%K contains[c] %@",keypath,value]; 107 | [predicates addObject:predicate]; 108 | }]; 109 | 110 | NSPredicate *resultPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicates]; 111 | return [self filteredArrayUsingPredicate:resultPredicate]; 112 | } 113 | 114 | 115 | - (void)each:(void(^)(id object))operation{ 116 | [self enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) { 117 | operation(object); 118 | }]; 119 | } 120 | 121 | - (void)eachWithIndex:(void(^)(id object, int index, BOOL *stop))operation{ 122 | [self enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) { 123 | operation(object, (int)idx, stop); 124 | }]; 125 | } 126 | 127 | -(NSArray*)sort{ 128 | return [self sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { 129 | return [a compare:b]; 130 | }]; 131 | } 132 | 133 | - (NSArray*)sort:(NSString*)key{ 134 | return [self sort:key ascending:YES]; 135 | } 136 | 137 | - (NSArray*)sort:(NSString*)key ascending:(BOOL)ascending{ 138 | NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:key ascending:ascending]; 139 | return [self sortedArrayUsingDescriptors:@[sortDescriptor]]; 140 | } 141 | 142 | - (NSArray*)sortWith:(NSComparisonResult (^)(id a, id b))callback{ 143 | return [self sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { 144 | return callback(a,b); 145 | }]; 146 | } 147 | 148 | - (NSArray*)reverse{ 149 | return [[self reverseObjectEnumerator] allObjects]; 150 | } 151 | 152 | - (NSArray*)slice:(int)howMany{ 153 | if(howMany > self.count) return @[]; 154 | return [self subarrayWithRange:NSMakeRange(howMany, self.count - howMany)]; 155 | } 156 | 157 | -(NSArray*)take:(int)howMany{ 158 | if(howMany > 0) 159 | return [self subarrayWithRange:NSMakeRange(0, MIN(howMany,self.count))]; 160 | else 161 | return [self subarrayWithRange:NSMakeRange(MAX(0, (int)self.count + howMany), MIN(-howMany,self.count))]; 162 | } 163 | 164 | -(NSArray*)splice:(int)howMany{ 165 | if([self isKindOfClass:[NSMutableArray class]]){ 166 | if(howMany > self.count) return @[]; 167 | NSArray* chunk = [self slice:howMany]; 168 | [(NSMutableArray*)self removeObjectsInRange:NSMakeRange(howMany, self.count - howMany)]; 169 | return chunk; 170 | } 171 | else{ 172 | [NSException raise:@"Array is not mutable" format:@"Array needs to be mutable"]; 173 | return nil; 174 | } 175 | } 176 | 177 | - (NSArray *)map:(id (^)(id obj, NSUInteger idx))block { 178 | NSMutableArray* result = [NSMutableArray arrayWithCapacity:self.count]; 179 | [self enumerateObjectsUsingBlock:^(id currentObject, NSUInteger index, BOOL *stop) { 180 | id mappedCurrentObject = block(currentObject, index); 181 | if (mappedCurrentObject) 182 | { 183 | [result addObject:mappedCurrentObject]; 184 | } 185 | }]; 186 | return result; 187 | } 188 | 189 | - (NSArray*)flatMap:(id (^)(id obj, NSUInteger idx))block{ 190 | NSMutableArray* results = [NSMutableArray new]; 191 | [self each:^(NSArray* array) { 192 | [results addObject:[array map:^id(id obj, NSUInteger idx) { 193 | return block(obj,idx); 194 | }]]; 195 | }]; 196 | return results; 197 | } 198 | 199 | - (NSArray*)flatMap:(NSString*)key block:(id (^)(id obj, NSUInteger idx))block{ 200 | NSMutableArray* results = [NSMutableArray new]; 201 | [self each:^(id object) { 202 | [results addObject:[[object valueForKey:key] map:^id(id obj, NSUInteger idx) { 203 | return block(obj,idx); 204 | }]]; 205 | }]; 206 | return results; 207 | } 208 | 209 | - (NSArray*)flatten{ 210 | NSMutableArray* results = [NSMutableArray new]; 211 | [self each:^(NSArray* array) { 212 | [results addObjectsFromArray:array]; 213 | }]; 214 | return results; 215 | } 216 | 217 | - (NSArray*)flatten:(NSString*)keypath{ 218 | NSMutableArray* results = [NSMutableArray new]; 219 | [self each:^(id object) { 220 | [results addObjectsFromArray:[object valueForKeyPath:keypath]]; 221 | }]; 222 | return results; 223 | } 224 | 225 | - (NSArray*)pluck:(NSString*)keyPath{ 226 | NSMutableArray *result = [NSMutableArray arrayWithCapacity:self.count]; 227 | [self each:^(id object) { 228 | [result addObject:[object valueForKeyPath:keyPath]]; 229 | }]; 230 | return result; 231 | } 232 | 233 | - (NSDictionary*)pluck:(NSString*)keyPath key:(NSString*)keyKeypath{ 234 | NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:self.count]; 235 | [self each:^(id object) { 236 | result[[object valueForKey:keyKeypath]] = [object valueForKey:keyPath]; 237 | }]; 238 | return result; 239 | } 240 | 241 | - (id)reduce:(id(^)(id carry, id object))block carry:(id)carry{ 242 | id __block carry2 = carry; 243 | [self each:^(id object) { 244 | carry2 = block(carry2,object); 245 | }]; 246 | return carry2; 247 | } 248 | 249 | - (id)reduce:(id(^)(id carry, id object))block{ 250 | return [self reduce:block carry:nil]; 251 | } 252 | 253 | - (id)pipe:(id (^)(NSArray* array))block{ 254 | return block(self); 255 | } 256 | 257 | - (id)when:(BOOL)condition block:(id (^)(NSArray* array))block{ 258 | if(condition) return block(self); 259 | return self; 260 | } 261 | 262 | - (NSDictionary*)groupBy:(NSString*)keypath{ 263 | return [self groupBy:keypath block:^NSString *(id object, NSString *key) { 264 | return key; 265 | }]; 266 | } 267 | 268 | - (NSDictionary*)groupBy:(NSString*)keypath block:(NSString*(^)(id object, NSString* key))block{ 269 | NSMutableDictionary *result = [NSMutableDictionary new]; 270 | 271 | NSString* finalKeypath = [NSString stringWithFormat:@"%@.@distinctUnionOfObjects.self",keypath]; 272 | NSArray *distinct = [self valueForKeyPath:finalKeypath]; 273 | 274 | [distinct each:^(NSString* value) { 275 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K = %@", keypath,value]; 276 | NSArray *objects = [self filteredArrayUsingPredicate:predicate]; 277 | [result setObject:objects forKey:block(objects[0],value)]; 278 | }]; 279 | 280 | return result; 281 | } 282 | 283 | - (NSDictionary*)expand:(NSString*)keypath{ 284 | return [self expand:keypath unique:NO]; 285 | } 286 | 287 | - (NSDictionary*)expand:(NSString *)keypath unique:(BOOL)unique{ 288 | if(unique) keypath = [NSString stringWithFormat:@"%@.@distinctUnionOfObjects.self",keypath]; 289 | 290 | NSMutableDictionary* result = [NSMutableDictionary new]; 291 | [self each:^(id object) { 292 | [[object valueForKeyPath:keypath] each:^(id key) { 293 | if(result[key] == nil) result[key] = [NSMutableArray new]; 294 | [result[key] addObject:object]; 295 | }]; 296 | }]; 297 | return result; 298 | } 299 | 300 | -(id)maxObject{ 301 | return [self reduce:^id(id carry, id object) { 302 | return (object > carry ) ? object : carry; 303 | } carry:self.firstObject]; 304 | } 305 | 306 | -(id)maxObject:(NSString *)keypath{ 307 | return [self reduce:^id(id carry, id object) { 308 | return ([[object valueForKeyPath:keypath] doubleValue] > [[carry valueForKeyPath:keypath] doubleValue]) ? object : carry; 309 | } carry:self.firstObject]; 310 | } 311 | 312 | -(id)maxObjectFor:(double(^)(id obj))block{ 313 | return [self reduce:^id(id carry, id object) { 314 | return block(object) > block(carry) ? object : carry; 315 | } carry:self.firstObject]; 316 | } 317 | 318 | -(id)minObject{ 319 | return [self reduce:^id(id carry, id object) { 320 | return (object < carry ) ? object : carry; 321 | } carry:self.firstObject]; 322 | } 323 | 324 | -(id)minObjectFor:(double(^)(id obj))block{ 325 | return [self reduce:^id(id carry, id object) { 326 | return block(object) < block(carry) ? object : carry; 327 | } carry:self.firstObject]; 328 | } 329 | 330 | -(id)minObject:(NSString *)keypath{ 331 | return [self reduce:^id(id carry, id object) { 332 | return ([[object valueForKeyPath:keypath] doubleValue] < [[carry valueForKeyPath:keypath] doubleValue] ) ? object : carry; 333 | } carry:self.firstObject]; 334 | } 335 | 336 | -(id)random{ 337 | NSUInteger randomIndex = arc4random() % self.count; 338 | return self[randomIndex]; 339 | } 340 | 341 | -(NSArray*)random:(int)quantity{ 342 | return [self.shuffled take:quantity]; 343 | } 344 | 345 | -(NSArray*)shuffled{ 346 | NSMutableArray* copy = self.mutableCopy; 347 | for (NSUInteger i = self.count; i > 1; i--) 348 | [copy exchangeObjectAtIndex:i - 1 withObjectAtIndex:arc4random_uniform((u_int32_t)i)]; 349 | 350 | return copy; 351 | } 352 | 353 | -(NSArray*)zip:(NSArray*)other{ 354 | NSInteger size = MIN(self.count, other.count); 355 | 356 | NSMutableArray *result = [NSMutableArray arrayWithCapacity:size]; 357 | for (NSUInteger idx = 0; idx < size; idx++) 358 | { 359 | [result addObject:[NSArray arrayWithObjects:[self objectAtIndex:idx], [other objectAtIndex:idx], nil]]; 360 | } 361 | 362 | return result; 363 | } 364 | 365 | -(NSDictionary*)mapToAssoc:(NSArray*(^)(id obj, NSUInteger idx))block{ 366 | NSArray* pairs = [self map:block]; 367 | 368 | return [pairs reduce:^id(NSMutableDictionary* dict, NSArray* mapped) { 369 | dict[mapped[0]] = mapped[1]; 370 | return dict; 371 | } carry:[NSMutableDictionary new]]; 372 | } 373 | 374 | -(NSCountedSet*)countedSet{ 375 | return [NSCountedSet setWithArray:self]; 376 | } 377 | 378 | -(NSString*)implode:(NSString*)delimiter{ 379 | return [self componentsJoinedByString:delimiter]; 380 | } 381 | 382 | -(NSString*)toString{ 383 | NSString* exploded = [self implode:@","]; 384 | return [NSString stringWithFormat:@"[%@]",exploded]; 385 | } 386 | 387 | -(NSString*)toJson{ 388 | NSError * err; 389 | NSData * jsonData = [NSJSONSerialization dataWithJSONObject:self options:0 error:&err]; 390 | return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 391 | } 392 | //============================================== 393 | #pragma mark - Operators 394 | //============================================== 395 | - (NSNumber*)operator:(NSString*)operator keypath:(NSString*)keypath{ 396 | NSString* finalKeyPath; 397 | if(keypath != nil) 398 | finalKeyPath = [NSString stringWithFormat:@"%@.@%@.self",keypath, operator]; 399 | else 400 | finalKeyPath = [NSString stringWithFormat:@"@%@.self",operator]; 401 | 402 | return [self valueForKeyPath:finalKeyPath]; 403 | } 404 | 405 | - (NSNumber*)sum { return [self operator:@"sum" keypath:nil]; } 406 | - (NSNumber*)sum:(NSString*)keypath { return [self operator:@"sum" keypath:keypath];} 407 | - (NSNumber*)avg { return [self operator:@"avg" keypath:nil]; } 408 | - (NSNumber*)avg:(NSString*)keypath { return [self operator:@"avg" keypath:keypath];} 409 | - (NSNumber*)max { return [self operator:@"max" keypath:nil]; } 410 | - (NSNumber*)max:(NSString*)keypath { return [self operator:@"max" keypath:keypath];} 411 | - (NSNumber*)min { return [self operator:@"min" keypath:nil]; } 412 | - (NSNumber*)min:(NSString*)keypath { return [self operator:@"min" keypath:keypath];} 413 | 414 | - (NSNumber*)sumWith:(NSNumber*(^)(id object))block{ 415 | return [self reduce:^id(NSNumber* carry, id object) { 416 | return @(carry.floatValue + block(object).floatValue); 417 | } carry:@(0)]; 418 | } 419 | 420 | //============================================== 421 | #pragma mark - Set operations 422 | //============================================== 423 | - (NSArray*)intersect:(NSArray*)b{ 424 | NSMutableOrderedSet *setA = [NSMutableOrderedSet orderedSetWithArray:self]; 425 | NSOrderedSet *setB = [NSOrderedSet orderedSetWithArray:b]; 426 | [setA intersectOrderedSet:setB]; 427 | return [setA array]; 428 | } 429 | 430 | - (NSArray*)union:(NSArray*)b{ 431 | NSMutableOrderedSet *setA = [NSMutableOrderedSet orderedSetWithArray:self]; 432 | NSOrderedSet *setB = [NSOrderedSet orderedSetWithArray:b]; 433 | [setA unionOrderedSet:setB]; 434 | return [setA array]; 435 | } 436 | 437 | - (NSArray*)minus:(NSArray*)b{ 438 | NSMutableOrderedSet *setA = [NSMutableOrderedSet orderedSetWithArray:self]; 439 | NSOrderedSet *setB = [NSOrderedSet orderedSetWithArray:b]; 440 | [setA minusOrderedSet:setB]; 441 | return [setA array]; 442 | } 443 | 444 | -(NSArray*)diff:(NSArray*)b{ 445 | return [self minus:b]; 446 | } 447 | 448 | - (NSArray*)join:(NSArray*)b{ 449 | return [self arrayByAddingObjectsFromArray:b]; 450 | } 451 | 452 | - (NSArray*)distinct{ 453 | NSOrderedSet *distinct = [NSOrderedSet orderedSetWithArray:self]; 454 | return [distinct array]; 455 | } 456 | 457 | - (NSArray*)distinct:(NSString*)keypath{ 458 | NSString* finalKeypath = [NSString stringWithFormat:@"%@.@distinctUnionOfObjects.self",keypath]; 459 | return [self valueForKeyPath:finalKeypath]; 460 | } 461 | 462 | -(NSArray*)crossJoin:(NSArray*)list{ 463 | if([list.firstObject isKindOfClass:NSArray.class]){ 464 | return [self.class cartesianProduct:[@[self] join:list]]; 465 | } 466 | return [self.class cartesianProduct:@[self, list]]; 467 | } 468 | 469 | +(NSArray*)cartesianProduct:(NSArray*)arrays{ 470 | int arraysCount = (int)arrays.count; 471 | unsigned long resultSize = 1; 472 | for (NSArray *array in arrays) 473 | resultSize *= array.count; 474 | NSMutableArray *product = [NSMutableArray arrayWithCapacity:resultSize]; 475 | for (unsigned long i = 0; i < resultSize; ++i) { 476 | NSMutableArray *cross = [NSMutableArray arrayWithCapacity:arraysCount]; 477 | [product addObject:cross]; 478 | unsigned long n = i; 479 | for (NSArray *array in arrays) { 480 | [cross addObject:[array objectAtIndex:n % array.count]]; 481 | n /= array.count; 482 | } 483 | } 484 | return product; 485 | } 486 | 487 | -(NSArray*)permutations{ 488 | NSMutableArray * permutations = [NSMutableArray new]; 489 | 490 | for (NSObject *object in self){ 491 | [permutations addObject:@[object]]; 492 | } 493 | 494 | for (int i = 1; i < self.count ; i++){ 495 | NSMutableArray *aCopy = permutations.copy; 496 | [permutations removeAllObjects]; 497 | 498 | for (NSObject *object in self){ 499 | for (NSArray *oldArray in aCopy){ 500 | if ([oldArray containsObject:object] == NO){ 501 | NSMutableArray *newArray = [NSMutableArray arrayWithArray:oldArray]; 502 | [newArray addObject:object]; 503 | [permutations addObject:newArray]; 504 | } 505 | } 506 | } 507 | } 508 | return permutations; 509 | } 510 | @end 511 | --------------------------------------------------------------------------------