CocoaPods trunk is moving to be read-only. Read more on the blog, there are 19 months to go.
TestsTested | ✓ |
LangLanguage | Obj-CObjective C |
License | BSD |
ReleasedLast Release | Mar 2015 |
Maintained by RJ Haydt.
REwriteDICTionary: a class that describes how to generate dictionary of key-value pairs with rewrite rules specifying dependencies of an input dictionary. It's an easy way to play around with dictionaries associated with from serialized/deserialized server requests/responses.
A RHRedict object contains a set of rewrite rules. Unlike other approaches, a rewrite rule maps from the output key back to the input key paths it depends on. For example, this fragment generates a dictionary with the keys: testName, latitude, longitude.
redict = [RHRedict new];
[redict addRuleForKey:@"testName" valueOfKeyPath:@"test_name" required:YES];
[redict addRuleForKey:@"latitude" valueOfKeyPath:@"location.lat" required:YES];
[redict addRuleForKey:@"longitude" valueOfKeyPath:@"location.long" required:YES];
Mapping each rule to a specific output key makes it much more obvious what the resulting dictionary looks like.
A redict object can be reused but conversion operations aren't re-entrant. For example, you can reuse a single redict to sequentially process each element of an array.
It's pretty simple to use. Create a new redict instance, add your rules, and apply the instance to an input dictionary.
A simple rewrite rule just sets a key in the output dictionary with the value of a key path in the input dictionary. For example:
[redict addRuleForKey:@"testName"
valueOfKeyPath:@"test_name" required:YES];
A more complex rule generates a key in the output dictionary by processing one or more values from the input dictionary using a block. The value for the key in the output dictionary is set to the object returned by the valueUsing block. For example:
[redict addRuleForKey:@"location"
valueOfKeyPaths:@[@"latitude",@"longitude"]
required:YES
valueUsing:^id(RHRewriteRule *rule,
NSDictionary *sourceDictionary) {
// generate a subdictionary for location with the lat,long
return @[
@"lat": sourceDictionary[@"latitude"],
@"long": sourceDictionary[@"longitude"]];
}];
The required flag indicates whether the keyword is expected to be present in the output dictionary.
The valueUsing block allows fully customized generation of a value for the rule's key. The block's arguments are the rule itself, and the input dictionary. From the rule, you can get the key name and the input key paths. Using the input key paths and the source dictionary, you can generate any object value for the key including a dictionary, array, or any other appropriate NSDictionary value. Return nil to prevent a dictionary entry for the key.
The NSDictionary+RHRedict extension provides a number of useful methods for type checking, conversion, value checking and default values.
A simple conversion just applies the rules and generates a new dictionary that contains all the required keys. For example:
NSDictionary *usefulResults = [redict dictionaryFrom:responseDictionary];
Or, there's a variation that allows that allows post-processing after all the rules have been applied. The completion block is always invoked even if there are missing keys. The redictResults has the results of applying the rewrite rules to the input dictionary. The completion block can return those results or an altered version or it can just return nil. For example:
NSDictionary *usefulResults = [redict
dictionaryFrom:responseDictionary
completion:^id(NSDictionary *redictResults, NSSet *missingKeys) { ...
}];
The missingKeys set contains a list of all the required keys that aren't present in the results dictionary. The value is nil if all required keys are present in the results.
The addRuleForKey methods return a reference to the newly generated rule. Any rule can optionally provide a missing value block. It's only invoked if the rule is marked as required and the key isn't present in the redictResults after all the rules have been processed. A rule's missingValue property block behaves the same as the valueUsing block.
A redict object can optionally provide a block to handle keys in the input dictionary that aren't referenced by the rules. The block can generate an output entry for the each input dictionary key as it sees fit. The defaultRule block behaves the same as a valueUsing block. The "rule" passed into the block is generated automatically for any otherwise unreferenced key present in the input dictionary.
The full processing sequence is: process all rules where the input dictionary keyPaths are present; use the defaultRule for any input keys that are unreferenced; generate missingValues for any required keys that aren't present in the results; and, finally, call the completion block with the rule results and any missing keys.
The example uses Google Places to retrieve a set of locations. You'll need to get an api key. Follow the developer directions in: http://developers.google.com/places/documentation/index to setup your console, get a "browser application key" and enable access to the service (iOS application keys don't work with Google Places).
To run the example project, clone the repo, and run pod install
from the Example directory.
You can just edit RHViewController and replace REDICT_GOOGLE_PLACE_KEY with your api key string. Or, if you create an environment variable called GOOGLE_PLACES_KEY with the api key, you don't have to edit the source. You can set the environment variable like this:
GOOGLE_PLACES_KEY="TheBrowserApplicationKeyFromYourGoogleConsole"
export GOOGLE_PLACES_KEY
Either way, once you're setup on google and have your api key, you can just build/run the example.
The pod itself has no dependencies. The Example depends on AFNetworking and, of course, the Google Places API.
RJ Haydt, technotes AT icloud DOT com
RHRedict is available under the BSD license. See the LICENSE file for more info.