Container+DeepSearch.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. //
  2. // Container+DeepSearch
  3. //
  4. // Created by Karl Stenerud on 2012-08-25.
  5. //
  6. // Copyright (c) 2012 Karl Stenerud. All rights reserved.
  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 remain in place
  16. // in this source code.
  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. /** Deep key search based methods for hierarchical container structures.
  27. *
  28. * A deep key search works like a normal search, except that the "key" is
  29. * interpreted as a series of keys, to be recursively applied in a "drill down"
  30. * fashion. There are two variants of each: the "deep key" variant, where the
  31. * key series is passed as an array, and the "key path" variant, where the
  32. * key series is passed as a serialized path, similar to filesystem paths
  33. * (a string where entries are separated by slashes).
  34. *
  35. * For example, if objectForDeepKey were called with [@"top", @"sublevel", @"2",
  36. * @"item] (or objectForKeyPath were called with @"top/sublevel/2/item"), it
  37. * would search as follows:
  38. *
  39. * result = [self objectForKey:@"top"];
  40. * result = [result objectForKey:@"sublevel"];
  41. * result = [result objectForKey:@"2"];
  42. * result = [result objectForKey:@"item"];
  43. *
  44. * Note that if any potential container along the way does not respond to
  45. * "objectForKey:", it will check to see if the container responds to
  46. * "objectAtIndex:" AND the current key responds to "intValue". If both do
  47. * respond, it will retrieve the current result using an array lookup:
  48. *
  49. * result = [result objectAtIndex:[currentKey intValue]];
  50. */
  51. #import <Foundation/Foundation.h>
  52. #pragma mark - NSDictionary -
  53. /**
  54. * Deep key search methods for NSDictionary.
  55. */
  56. @interface NSDictionary (DeepSearch)
  57. #pragma mark - Lookups
  58. /** Do a deep search using the specified keys.
  59. *
  60. * A failed lookup returns nil, except in the case of a failed array-style
  61. * lookup, in which case it may throw an "index out of range" exception.
  62. *
  63. * @param deepKey A set of keys to drill down with.
  64. */
  65. - (id) objectForDeepKey:(NSArray*) deepKey;
  66. /** Do a deep search using the specified keys.
  67. *
  68. * A failed lookup returns nil, except in the case of a failed array-style
  69. * lookup, in which case it may throw an "index out of range" exception.
  70. *
  71. * @param keyPath A full key path, separated by slash (e.g. @"a/b/c")
  72. */
  73. - (id) objectForKeyPath:(NSString*) keyPath;
  74. #pragma mark - Mutators
  75. /** Set an associated object at the specified deep key.
  76. *
  77. * The object will be stored either dictionary style "setObject:forKey:" or
  78. * array style "replaceObjectAtIndex:withObject:", depending on what the
  79. * final container object responds to.
  80. *
  81. * If the lookup fails at any level, it will throw an exception describing which
  82. * object in the hierarchy did not respond to any object accessor methods.
  83. */
  84. - (void) setObject:(id) anObject forDeepKey:(NSArray*) deepKey;
  85. /** Set an associated object at the specified key path.
  86. *
  87. * The object will be stored either dictionary style "setObject:forKey:" or
  88. * array style "replaceObjectAtIndex:withObject:", depending on what the
  89. * final container object responds to.
  90. *
  91. * If the lookup fails at any level, it will throw an exception describing which
  92. * object in the hierarchy did not respond to any object accessor methods.
  93. */
  94. - (void) setObject:(id) anObject forKeyPath:(NSString*) keyPath;
  95. /** Remove an associated object at the specified deep key.
  96. *
  97. * The object will be stored either dictionary style "removeObjectForKey:" or
  98. * array style "removeObjectAtIndex:", depending on what the final container
  99. * object responds to.
  100. *
  101. * If the lookup fails at any level, it will throw an exception describing which
  102. * object in the hierarchy did not respond to any object accessor methods.
  103. */
  104. - (void) removeObjectForDeepKey:(NSArray*) deepKey;
  105. /** Remove an associated object at the specified key path.
  106. *
  107. * The object will be stored either dictionary style "removeObjectForKey:" or
  108. * array style "removeObjectAtIndex:", depending on what the final container
  109. * object responds to.
  110. *
  111. * If the lookup fails at any level, it will throw an exception describing which
  112. * object in the hierarchy did not respond to any object accessor methods.
  113. */
  114. - (void) removeObjectForKeyPath:(NSString*) keyPath;
  115. @end
  116. #pragma mark - NSArray -
  117. /**
  118. * Deep key search methods for NSDictionary.
  119. */
  120. @interface NSArray (DeepSearch)
  121. #pragma mark - Lookups
  122. /** Do a deep search using the specified keys.
  123. *
  124. * A failed lookup returns nil, except in the case of a failed array-style
  125. * lookup, in which case it may throw an "index out of range" exception.
  126. *
  127. * @param deepKey A set of keys to drill down with.
  128. */
  129. - (id) objectForDeepKey:(NSArray*) deepKey;
  130. /** Do a deep search using the specified keys.
  131. *
  132. * A failed lookup returns nil, except in the case of a failed array-style
  133. * lookup, in which case it may throw an "index out of range" exception.
  134. *
  135. * @param keyPath A full key path, separated by slash (e.g. @"a/b/c")
  136. */
  137. - (id) objectForKeyPath:(NSString*) keyPath;
  138. #pragma mark - Mutators
  139. /** Set an associated object at the specified deep key.
  140. *
  141. * The object will be stored either dictionary style "setObject:forKey:" or
  142. * array style "replaceObjectAtIndex:withObject:", depending on what the
  143. * final container object responds to.
  144. *
  145. * If the lookup fails at any level, it will throw an exception describing which
  146. * object in the hierarchy did not respond to any object accessor methods.
  147. */
  148. - (void) setObject:(id) anObject forDeepKey:(NSArray*) deepKey;
  149. /** Set an associated object at the specified key path.
  150. *
  151. * The object will be stored either dictionary style "setObject:forKey:" or
  152. * array style "replaceObjectAtIndex:withObject:", depending on what the
  153. * final container object responds to.
  154. *
  155. * If the lookup fails at any level, it will throw an exception describing which
  156. * object in the hierarchy did not respond to any object accessor methods.
  157. */
  158. - (void) setObject:(id) anObject forKeyPath:(NSString*) keyPath;
  159. /** Remove an associated object at the specified deep key.
  160. *
  161. * The object will be stored either dictionary style "removeObjectForKey:" or
  162. * array style "removeObjectAtIndex:", depending on what the final container
  163. * object responds to.
  164. *
  165. * If the lookup fails at any level, it will throw an exception describing which
  166. * object in the hierarchy did not respond to any object accessor methods.
  167. */
  168. - (void) removeObjectForDeepKey:(NSArray*) deepKey;
  169. /** Remove an associated object at the specified key path.
  170. *
  171. * The object will be stored either dictionary style "removeObjectForKey:" or
  172. * array style "removeObjectAtIndex:", depending on what the final container
  173. * object responds to.
  174. *
  175. * If the lookup fails at any level, it will throw an exception describing which
  176. * object in the hierarchy did not respond to any object accessor methods.
  177. */
  178. - (void) removeObjectForKeyPath:(NSString*) keyPath;
  179. @end