xcres 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (299) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.travis.yml +18 -0
  4. data/Gemfile +8 -0
  5. data/Gemfile.lock +85 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +181 -0
  8. data/Rakefile +58 -0
  9. data/bin/xcres +12 -0
  10. data/lib/xcres/analyzer/aggregate_analyzer.rb +48 -0
  11. data/lib/xcres/analyzer/analyzer.rb +141 -0
  12. data/lib/xcres/analyzer/resources_aggregate_analyzer.rb +27 -0
  13. data/lib/xcres/analyzer/resources_analyzer/base_resources_analyzer.rb +133 -0
  14. data/lib/xcres/analyzer/resources_analyzer/bundle_resources_analyzer.rb +68 -0
  15. data/lib/xcres/analyzer/resources_analyzer/loose_resources_analyzer.rb +39 -0
  16. data/lib/xcres/analyzer/resources_analyzer/xcassets_analyzer.rb +62 -0
  17. data/lib/xcres/analyzer/strings_analyzer.rb +255 -0
  18. data/lib/xcres/builder/file_builder.rb +61 -0
  19. data/lib/xcres/builder/resources_builder.rb +184 -0
  20. data/lib/xcres/builder/string_builder.rb +31 -0
  21. data/lib/xcres/command/build_command.rb +83 -0
  22. data/lib/xcres/command/command.rb +58 -0
  23. data/lib/xcres/command/install_command.rb +173 -0
  24. data/lib/xcres/command/main_command.rb +14 -0
  25. data/lib/xcres/command/project_command.rb +111 -0
  26. data/lib/xcres/command/version_command.rb +12 -0
  27. data/lib/xcres/helper/file_helper.rb +16 -0
  28. data/lib/xcres/logger.rb +148 -0
  29. data/lib/xcres/model/section.rb +43 -0
  30. data/lib/xcres/model/xcassets/bundle.rb +55 -0
  31. data/lib/xcres/model/xcassets/resource.rb +141 -0
  32. data/lib/xcres/model/xcassets/resource_image.rb +134 -0
  33. data/lib/xcres/version.rb +9 -0
  34. data/lib/xcres.rb +9 -0
  35. data/spec/fixtures/Example/Example/AppDelegate.h +15 -0
  36. data/spec/fixtures/Example/Example/AppDelegate.m +49 -0
  37. data/spec/fixtures/Example/Example/Example-Info.plist +38 -0
  38. data/spec/fixtures/Example/Example/Example-Prefix.pch +16 -0
  39. data/spec/fixtures/Example/Example/Images/doge.jpeg +0 -0
  40. data/spec/fixtures/Example/Example/Images/nyanCat.png +0 -0
  41. data/spec/fixtures/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  42. data/spec/fixtures/Example/Example/Images.xcassets/Doge.imageset/Contents.json +18 -0
  43. data/spec/fixtures/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
  44. data/spec/fixtures/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
  45. data/spec/fixtures/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  46. data/spec/fixtures/Example/Example/de.lproj/Localizable.strings +12 -0
  47. data/spec/fixtures/Example/Example/en.lproj/InfoPlist.strings +2 -0
  48. data/spec/fixtures/Example/Example/en.lproj/Localizable.strings +15 -0
  49. data/spec/fixtures/Example/Example/main.m +18 -0
  50. data/spec/fixtures/Example/Example.xcodeproj/project.pbxproj +449 -0
  51. data/spec/fixtures/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  52. data/spec/fixtures/ExampleOSX/ExampleOSX/AppDelegate.h +15 -0
  53. data/spec/fixtures/ExampleOSX/ExampleOSX/AppDelegate.m +18 -0
  54. data/spec/fixtures/ExampleOSX/ExampleOSX/Base.lproj/MainMenu.xib +680 -0
  55. data/spec/fixtures/ExampleOSX/ExampleOSX/ExampleOSX-Info.plist +34 -0
  56. data/spec/fixtures/ExampleOSX/ExampleOSX/ExampleOSX-Prefix.pch +9 -0
  57. data/spec/fixtures/ExampleOSX/ExampleOSX/Images.xcassets/AppIcon.appiconset/Contents.json +58 -0
  58. data/spec/fixtures/ExampleOSX/ExampleOSX/en.lproj/Credits.rtf +29 -0
  59. data/spec/fixtures/ExampleOSX/ExampleOSX/en.lproj/InfoPlist.strings +2 -0
  60. data/spec/fixtures/ExampleOSX/ExampleOSX/main.m +14 -0
  61. data/spec/fixtures/ExampleOSX/ExampleOSX.xcodeproj/project.pbxproj +481 -0
  62. data/spec/fixtures/ExampleOSX/ExampleOSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  63. data/spec/fixtures/ExampleOSX/ExampleOSXTests/ExampleOSXTests-Info.plist +22 -0
  64. data/spec/fixtures/ExampleOSX/ExampleOSXTests/ExampleOSXTests.m +34 -0
  65. data/spec/fixtures/ExampleOSX/ExampleOSXTests/en.lproj/InfoPlist.strings +2 -0
  66. data/spec/integration/build/after/Example/Example/AppDelegate.h +15 -0
  67. data/spec/integration/build/after/Example/Example/AppDelegate.m +49 -0
  68. data/spec/integration/build/after/Example/Example/Example-Info.plist +38 -0
  69. data/spec/integration/build/after/Example/Example/Example-Prefix.pch +16 -0
  70. data/spec/integration/build/after/Example/Example/Icons.bundle/tab_bar/tabbar_list.png +0 -0
  71. data/spec/integration/build/after/Example/Example/Icons.bundle/tab_bar/tabbar_list@2x.png +0 -0
  72. data/spec/integration/build/after/Example/Example/Icons.bundle/tab_bar/tabbar_map.png +0 -0
  73. data/spec/integration/build/after/Example/Example/Icons.bundle/tab_bar/tabbar_map@2x.png +0 -0
  74. data/spec/integration/build/after/Example/Example/Images/doge.jpeg +0 -0
  75. data/spec/integration/build/after/Example/Example/Images/nyanCat.png +0 -0
  76. data/spec/integration/build/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  77. data/spec/integration/build/after/Example/Example/Images.xcassets/Doge.imageset/Contents.json +18 -0
  78. data/spec/integration/build/after/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
  79. data/spec/integration/build/after/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
  80. data/spec/integration/build/after/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  81. data/spec/integration/build/after/Example/Example/de.lproj/Localizable.strings +12 -0
  82. data/spec/integration/build/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
  83. data/spec/integration/build/after/Example/Example/en.lproj/Localizable.strings +15 -0
  84. data/spec/integration/build/after/Example/Example/main.m +18 -0
  85. data/spec/integration/build/after/Example/Example.xcodeproj.yaml +168 -0
  86. data/spec/integration/build/after/R.h +39 -0
  87. data/spec/integration/build/after/R.m +29 -0
  88. data/spec/integration/build/after/execution_output.txt +19 -0
  89. data/spec/integration/build/before/Example/Example/AppDelegate.h +15 -0
  90. data/spec/integration/build/before/Example/Example/AppDelegate.m +49 -0
  91. data/spec/integration/build/before/Example/Example/Example-Info.plist +38 -0
  92. data/spec/integration/build/before/Example/Example/Example-Prefix.pch +16 -0
  93. data/spec/integration/build/before/Example/Example/Icons.bundle/tab_bar/tabbar_list.png +0 -0
  94. data/spec/integration/build/before/Example/Example/Icons.bundle/tab_bar/tabbar_list@2x.png +0 -0
  95. data/spec/integration/build/before/Example/Example/Icons.bundle/tab_bar/tabbar_map.png +0 -0
  96. data/spec/integration/build/before/Example/Example/Icons.bundle/tab_bar/tabbar_map@2x.png +0 -0
  97. data/spec/integration/build/before/Example/Example/Images/doge.jpeg +0 -0
  98. data/spec/integration/build/before/Example/Example/Images/nyanCat.png +0 -0
  99. data/spec/integration/build/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  100. data/spec/integration/build/before/Example/Example/Images.xcassets/Doge.imageset/Contents.json +18 -0
  101. data/spec/integration/build/before/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
  102. data/spec/integration/build/before/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
  103. data/spec/integration/build/before/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  104. data/spec/integration/build/before/Example/Example/de.lproj/Localizable.strings +12 -0
  105. data/spec/integration/build/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
  106. data/spec/integration/build/before/Example/Example/en.lproj/Localizable.strings +15 -0
  107. data/spec/integration/build/before/Example/Example/main.m +18 -0
  108. data/spec/integration/build/before/Example/Example.xcodeproj/project.pbxproj +453 -0
  109. data/spec/integration/build/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  110. data/spec/integration/build-keyword-clash/after/Example/Example/AppDelegate.h +15 -0
  111. data/spec/integration/build-keyword-clash/after/Example/Example/AppDelegate.m +49 -0
  112. data/spec/integration/build-keyword-clash/after/Example/Example/Default-568h@2x.png +0 -0
  113. data/spec/integration/build-keyword-clash/after/Example/Example/Default.png +0 -0
  114. data/spec/integration/build-keyword-clash/after/Example/Example/Default@2x.png +0 -0
  115. data/spec/integration/build-keyword-clash/after/Example/Example/Example-Info.plist +38 -0
  116. data/spec/integration/build-keyword-clash/after/Example/Example/Example-Prefix.pch +16 -0
  117. data/spec/integration/build-keyword-clash/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  118. data/spec/integration/build-keyword-clash/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
  119. data/spec/integration/build-keyword-clash/after/Example/Example/main.m +18 -0
  120. data/spec/integration/build-keyword-clash/after/Example/Example.xcodeproj.yaml +160 -0
  121. data/spec/integration/build-keyword-clash/after/R.h +15 -0
  122. data/spec/integration/build-keyword-clash/after/R.m +15 -0
  123. data/spec/integration/build-keyword-clash/after/execution_output.txt +14 -0
  124. data/spec/integration/build-keyword-clash/before/Example/Example/AppDelegate.h +15 -0
  125. data/spec/integration/build-keyword-clash/before/Example/Example/AppDelegate.m +49 -0
  126. data/spec/integration/build-keyword-clash/before/Example/Example/Default-568h@2x.png +0 -0
  127. data/spec/integration/build-keyword-clash/before/Example/Example/Default.png +0 -0
  128. data/spec/integration/build-keyword-clash/before/Example/Example/Default@2x.png +0 -0
  129. data/spec/integration/build-keyword-clash/before/Example/Example/Example-Info.plist +38 -0
  130. data/spec/integration/build-keyword-clash/before/Example/Example/Example-Prefix.pch +16 -0
  131. data/spec/integration/build-keyword-clash/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  132. data/spec/integration/build-keyword-clash/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
  133. data/spec/integration/build-keyword-clash/before/Example/Example/main.m +18 -0
  134. data/spec/integration/build-keyword-clash/before/Example/Example.xcodeproj/project.pbxproj +427 -0
  135. data/spec/integration/build-keyword-clash/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  136. data/spec/integration/build-var-infoplist/after/Example/Example/AppDelegate.h +15 -0
  137. data/spec/integration/build-var-infoplist/after/Example/Example/AppDelegate.m +49 -0
  138. data/spec/integration/build-var-infoplist/after/Example/Example/Example-Info.plist +38 -0
  139. data/spec/integration/build-var-infoplist/after/Example/Example/Example-Prefix.pch +16 -0
  140. data/spec/integration/build-var-infoplist/after/Example/Example/Icons.bundle/tab_bar/tabbar_list.png +0 -0
  141. data/spec/integration/build-var-infoplist/after/Example/Example/Icons.bundle/tab_bar/tabbar_list@2x.png +0 -0
  142. data/spec/integration/build-var-infoplist/after/Example/Example/Icons.bundle/tab_bar/tabbar_map.png +0 -0
  143. data/spec/integration/build-var-infoplist/after/Example/Example/Icons.bundle/tab_bar/tabbar_map@2x.png +0 -0
  144. data/spec/integration/build-var-infoplist/after/Example/Example/Images/doge.jpeg +0 -0
  145. data/spec/integration/build-var-infoplist/after/Example/Example/Images/nyanCat.png +0 -0
  146. data/spec/integration/build-var-infoplist/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  147. data/spec/integration/build-var-infoplist/after/Example/Example/Images.xcassets/Doge.imageset/Contents.json +18 -0
  148. data/spec/integration/build-var-infoplist/after/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
  149. data/spec/integration/build-var-infoplist/after/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
  150. data/spec/integration/build-var-infoplist/after/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  151. data/spec/integration/build-var-infoplist/after/Example/Example/de.lproj/Localizable.strings +12 -0
  152. data/spec/integration/build-var-infoplist/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
  153. data/spec/integration/build-var-infoplist/after/Example/Example/en.lproj/Localizable.strings +15 -0
  154. data/spec/integration/build-var-infoplist/after/Example/Example/main.m +18 -0
  155. data/spec/integration/build-var-infoplist/after/Example/Example.xcodeproj.yaml +168 -0
  156. data/spec/integration/build-var-infoplist/after/R.h +39 -0
  157. data/spec/integration/build-var-infoplist/after/R.m +29 -0
  158. data/spec/integration/build-var-infoplist/after/execution_output.txt +19 -0
  159. data/spec/integration/build-var-infoplist/before/Example/Example/AppDelegate.h +15 -0
  160. data/spec/integration/build-var-infoplist/before/Example/Example/AppDelegate.m +49 -0
  161. data/spec/integration/build-var-infoplist/before/Example/Example/Example-Info.plist +38 -0
  162. data/spec/integration/build-var-infoplist/before/Example/Example/Example-Prefix.pch +16 -0
  163. data/spec/integration/build-var-infoplist/before/Example/Example/Icons.bundle/tab_bar/tabbar_list.png +0 -0
  164. data/spec/integration/build-var-infoplist/before/Example/Example/Icons.bundle/tab_bar/tabbar_list@2x.png +0 -0
  165. data/spec/integration/build-var-infoplist/before/Example/Example/Icons.bundle/tab_bar/tabbar_map.png +0 -0
  166. data/spec/integration/build-var-infoplist/before/Example/Example/Icons.bundle/tab_bar/tabbar_map@2x.png +0 -0
  167. data/spec/integration/build-var-infoplist/before/Example/Example/Images/doge.jpeg +0 -0
  168. data/spec/integration/build-var-infoplist/before/Example/Example/Images/nyanCat.png +0 -0
  169. data/spec/integration/build-var-infoplist/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  170. data/spec/integration/build-var-infoplist/before/Example/Example/Images.xcassets/Doge.imageset/Contents.json +18 -0
  171. data/spec/integration/build-var-infoplist/before/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
  172. data/spec/integration/build-var-infoplist/before/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
  173. data/spec/integration/build-var-infoplist/before/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  174. data/spec/integration/build-var-infoplist/before/Example/Example/de.lproj/Localizable.strings +12 -0
  175. data/spec/integration/build-var-infoplist/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
  176. data/spec/integration/build-var-infoplist/before/Example/Example/en.lproj/Localizable.strings +15 -0
  177. data/spec/integration/build-var-infoplist/before/Example/Example/main.m +18 -0
  178. data/spec/integration/build-var-infoplist/before/Example/Example.xcodeproj/project.pbxproj +453 -0
  179. data/spec/integration/build-var-infoplist/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  180. data/spec/integration/help/after/execution_output.txt +18 -0
  181. data/spec/integration/help/before/.gitkeep +0 -0
  182. data/spec/integration/install/after/Example/Example/AppDelegate.h +15 -0
  183. data/spec/integration/install/after/Example/Example/AppDelegate.m +49 -0
  184. data/spec/integration/install/after/Example/Example/Example-Info.plist +38 -0
  185. data/spec/integration/install/after/Example/Example/Example-Prefix.pch +18 -0
  186. data/spec/integration/install/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  187. data/spec/integration/install/after/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  188. data/spec/integration/install/after/Example/Example/Resources/R.h +19 -0
  189. data/spec/integration/install/after/Example/Example/Resources/R.m +17 -0
  190. data/spec/integration/install/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
  191. data/spec/integration/install/after/Example/Example/main.m +18 -0
  192. data/spec/integration/install/after/Example/Example.xcodeproj/project.pbxproj +898 -0
  193. data/spec/integration/install/after/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  194. data/spec/integration/install/after/Example/Example.xcodeproj.yaml +172 -0
  195. data/spec/integration/install/after/execution_output.txt +22 -0
  196. data/spec/integration/install/before/Example/Example/AppDelegate.h +15 -0
  197. data/spec/integration/install/before/Example/Example/AppDelegate.m +49 -0
  198. data/spec/integration/install/before/Example/Example/Example-Info.plist +38 -0
  199. data/spec/integration/install/before/Example/Example/Example-Prefix.pch +16 -0
  200. data/spec/integration/install/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  201. data/spec/integration/install/before/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  202. data/spec/integration/install/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
  203. data/spec/integration/install/before/Example/Example/main.m +18 -0
  204. data/spec/integration/install/before/Example/Example.xcodeproj/project.pbxproj +421 -0
  205. data/spec/integration/install/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  206. data/spec/integration/install-again/after/Example/Example/AppDelegate.h +15 -0
  207. data/spec/integration/install-again/after/Example/Example/AppDelegate.m +49 -0
  208. data/spec/integration/install-again/after/Example/Example/Example-Info.plist +38 -0
  209. data/spec/integration/install-again/after/Example/Example/Example-Prefix.pch +18 -0
  210. data/spec/integration/install-again/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  211. data/spec/integration/install-again/after/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  212. data/spec/integration/install-again/after/Example/Example/Resources/R.h +19 -0
  213. data/spec/integration/install-again/after/Example/Example/Resources/R.m +17 -0
  214. data/spec/integration/install-again/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
  215. data/spec/integration/install-again/after/Example/Example/main.m +18 -0
  216. data/spec/integration/install-again/after/Example/Example.xcodeproj.yaml +172 -0
  217. data/spec/integration/install-again/after/execution_output.txt +23 -0
  218. data/spec/integration/install-again/before/Example/Example/AppDelegate.h +15 -0
  219. data/spec/integration/install-again/before/Example/Example/AppDelegate.m +49 -0
  220. data/spec/integration/install-again/before/Example/Example/Example-Info.plist +38 -0
  221. data/spec/integration/install-again/before/Example/Example/Example-Prefix.pch +18 -0
  222. data/spec/integration/install-again/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  223. data/spec/integration/install-again/before/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  224. data/spec/integration/install-again/before/Example/Example/Resources/R.h +19 -0
  225. data/spec/integration/install-again/before/Example/Example/Resources/R.m +17 -0
  226. data/spec/integration/install-again/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
  227. data/spec/integration/install-again/before/Example/Example/main.m +18 -0
  228. data/spec/integration/install-again/before/Example/Example.xcodeproj/project.pbxproj +898 -0
  229. data/spec/integration/install-again/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  230. data/spec/integration/install-moved-supporting-files/after/Example/Example.xcodeproj.yaml +173 -0
  231. data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/Example-Info.plist +38 -0
  232. data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/Example-Prefix.pch +18 -0
  233. data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/Resources/R.h +19 -0
  234. data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/Resources/R.m +17 -0
  235. data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/en.lproj/InfoPlist.strings +2 -0
  236. data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/main.m +18 -0
  237. data/spec/integration/install-moved-supporting-files/after/Example/res/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  238. data/spec/integration/install-moved-supporting-files/after/Example/res/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  239. data/spec/integration/install-moved-supporting-files/after/Example/src/AppDelegate.h +15 -0
  240. data/spec/integration/install-moved-supporting-files/after/Example/src/AppDelegate.m +49 -0
  241. data/spec/integration/install-moved-supporting-files/after/execution_output.txt +22 -0
  242. data/spec/integration/install-moved-supporting-files/before/Example/Example.xcodeproj/project.pbxproj +431 -0
  243. data/spec/integration/install-moved-supporting-files/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  244. data/spec/integration/install-moved-supporting-files/before/Example/Supporting_Files/Example-Info.plist +38 -0
  245. data/spec/integration/install-moved-supporting-files/before/Example/Supporting_Files/Example-Prefix.pch +16 -0
  246. data/spec/integration/install-moved-supporting-files/before/Example/Supporting_Files/en.lproj/InfoPlist.strings +2 -0
  247. data/spec/integration/install-moved-supporting-files/before/Example/Supporting_Files/main.m +18 -0
  248. data/spec/integration/install-moved-supporting-files/before/Example/res/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  249. data/spec/integration/install-moved-supporting-files/before/Example/res/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  250. data/spec/integration/install-moved-supporting-files/before/Example/src/AppDelegate.h +15 -0
  251. data/spec/integration/install-moved-supporting-files/before/Example/src/AppDelegate.m +49 -0
  252. data/spec/integration/install-no-supporting-files/after/Example/Example.xcodeproj.yaml +173 -0
  253. data/spec/integration/install-no-supporting-files/after/Example/Resources/R.h +19 -0
  254. data/spec/integration/install-no-supporting-files/after/Example/Resources/R.m +17 -0
  255. data/spec/integration/install-no-supporting-files/after/Example/Supporting_Files/Example-Info.plist +38 -0
  256. data/spec/integration/install-no-supporting-files/after/Example/Supporting_Files/Example-Prefix.pch +18 -0
  257. data/spec/integration/install-no-supporting-files/after/Example/Supporting_Files/en.lproj/InfoPlist.strings +2 -0
  258. data/spec/integration/install-no-supporting-files/after/Example/Supporting_Files/main.m +18 -0
  259. data/spec/integration/install-no-supporting-files/after/Example/res/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  260. data/spec/integration/install-no-supporting-files/after/Example/res/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  261. data/spec/integration/install-no-supporting-files/after/Example/src/AppDelegate.h +15 -0
  262. data/spec/integration/install-no-supporting-files/after/Example/src/AppDelegate.m +49 -0
  263. data/spec/integration/install-no-supporting-files/after/execution_output.txt +23 -0
  264. data/spec/integration/install-no-supporting-files/before/Example/Example.xcodeproj/project.pbxproj +430 -0
  265. data/spec/integration/install-no-supporting-files/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  266. data/spec/integration/install-no-supporting-files/before/Example/Supporting_Files/Example-Info.plist +38 -0
  267. data/spec/integration/install-no-supporting-files/before/Example/Supporting_Files/Example-Prefix.pch +16 -0
  268. data/spec/integration/install-no-supporting-files/before/Example/Supporting_Files/en.lproj/InfoPlist.strings +2 -0
  269. data/spec/integration/install-no-supporting-files/before/Example/Supporting_Files/main.m +18 -0
  270. data/spec/integration/install-no-supporting-files/before/Example/res/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  271. data/spec/integration/install-no-supporting-files/before/Example/res/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  272. data/spec/integration/install-no-supporting-files/before/Example/src/AppDelegate.h +15 -0
  273. data/spec/integration/install-no-supporting-files/before/Example/src/AppDelegate.m +49 -0
  274. data/spec/integration/version/after/execution_output.txt +3 -0
  275. data/spec/integration/version/before/.gitkeep +0 -0
  276. data/spec/integration.rb +86 -0
  277. data/spec/spec_helper/xcodeproj_project_yaml.rb +26 -0
  278. data/spec/unit/analyzer/aggregate_analyzer_spec.rb +61 -0
  279. data/spec/unit/analyzer/analyzer_spec.rb +123 -0
  280. data/spec/unit/analyzer/resources_aggregate_analyzer_spec.rb +46 -0
  281. data/spec/unit/analyzer/resources_analyzer/base_resources_analyzer_spec.rb +126 -0
  282. data/spec/unit/analyzer/resources_analyzer/bundle_resources_analyzer_spec.rb +57 -0
  283. data/spec/unit/analyzer/resources_analyzer/loose_resources_analyzer_spec.rb +22 -0
  284. data/spec/unit/analyzer/strings_analyzer_spec.rb +99 -0
  285. data/spec/unit/builder/file_builder_spec.rb +46 -0
  286. data/spec/unit/builder/resources_builder_spec.rb +50 -0
  287. data/spec/unit/builder/string_builder_spec.rb +76 -0
  288. data/spec/unit/command/main_command_spec.rb +5 -0
  289. data/spec/unit/command/project_command_spec.rb +23 -0
  290. data/spec/unit/helper/file_helper_spec.rb +24 -0
  291. data/spec/unit/logger_spec.rb +142 -0
  292. data/spec/unit/model/section_spec.rb +47 -0
  293. data/spec/unit/model/xcassets/bundle_spec.rb +154 -0
  294. data/spec/unit/model/xcassets/resource_image_spec.rb +141 -0
  295. data/spec/unit/model/xcassets/resource_spec.rb +174 -0
  296. data/spec/unit/model/xcassets/spec_helper.rb +31 -0
  297. data/spec/unit/spec_helper.rb +17 -0
  298. data/xcres.gemspec +42 -0
  299. metadata +811 -0
@@ -0,0 +1,184 @@
1
+ require 'xcres/builder/file_builder'
2
+ require 'xcres/helper/file_helper'
3
+
4
+ class XCRes::ResourcesBuilder < XCRes::FileBuilder
5
+
6
+ include XCRes::FileHelper
7
+
8
+ BANNER = <<EOS
9
+ // generated by xcres
10
+ //
11
+ // DO NOT EDIT. This file is machine-generated and constantly overwritten.
12
+ // See https://github.com/mrackwitz/xcres for more info.
13
+ //
14
+ EOS
15
+
16
+ COMPILER_KEYWORDS = %w{
17
+ auto break case char const continue default do double else enum extern float
18
+ for goto if inline int long register restrict return short signed sizeof
19
+ static struct switch typedef union unsigned void volatile while
20
+ }
21
+
22
+ # @return [String]
23
+ # the name of the constant in the generated file(s)
24
+ attr_accessor :resources_constant_name
25
+
26
+ # @return [Bool]
27
+ # whether the generated resources constant should contain inline
28
+ # documentation for each key, true by default
29
+ attr_accessor :documented
30
+ alias :documented? :documented
31
+
32
+ # @return [Hash{String => {String => String}}]
33
+ # the sections, which will been written to the built files
34
+ attr_reader :sections
35
+
36
+ # Initialize a new instance
37
+ #
38
+ def initialize
39
+ @sections = {}
40
+ self.documented = true
41
+ end
42
+
43
+ # Extract resource name from #output_path, if not customized
44
+ #
45
+ # @return [String]
46
+ #
47
+ def resources_constant_name
48
+ @resources_constant_name ||= basename_without_ext output_path
49
+ end
50
+
51
+ def add_section name, items, options = {}
52
+ raise ArgumentError.new 'No items given!' if items.nil?
53
+
54
+ transformed_items = {}
55
+
56
+ for key, value in items
57
+ transformed_key = transform_key key, options
58
+
59
+ # Skip invalid key names
60
+ if transformed_key.length == 0
61
+ logger.warn "Skip invalid key: '%s'. (Was transformed to empty text)", key
62
+ next
63
+ end
64
+
65
+ # Skip compiler keywords
66
+ if COMPILER_KEYWORDS.include? transformed_key
67
+ logger.warn "Skip invalid key: '%s'. (Was transformed to keyword '%s')", key, transformed_key
68
+ next
69
+ end
70
+
71
+ transformed_items[transformed_key] = value
72
+ end
73
+
74
+ @sections[name] = transformed_items
75
+ end
76
+
77
+ def build
78
+ super
79
+
80
+ # Build file contents and write them to disk
81
+ write_file_eventually "#{output_path}.h", (build_contents do |h_file|
82
+ build_header_contents h_file
83
+ end)
84
+
85
+ write_file_eventually "#{output_path}.m", (build_contents do |m_file|
86
+ build_impl_contents m_file
87
+ end)
88
+ end
89
+
90
+ protected
91
+
92
+ def transform_key key, options
93
+ # Split the key into components
94
+ components = key.underscore.split /[_\/ ]/
95
+
96
+ # Build the new key incremental
97
+ result = ''
98
+
99
+ for component in components
100
+ # Ignore empty components
101
+ next unless component.length > 0
102
+
103
+ # Ignore components which are already contained in the key, if enabled
104
+ if options[:shorten_keys]
105
+ next unless result.downcase.scan(component).blank?
106
+ end
107
+
108
+ # Clean component from non alphanumeric characters
109
+ clean_component = component.gsub /[^a-zA-Z0-9]/, ''
110
+
111
+ # Skip if empty
112
+ next unless clean_component.length > 0
113
+
114
+ if result.length == 0
115
+ result += clean_component
116
+ else
117
+ result += clean_component[0].upcase + clean_component[1..-1]
118
+ end
119
+ end
120
+
121
+ result
122
+ end
123
+
124
+ def build_header_contents h_file
125
+ h_file.writeln BANNER
126
+ h_file.writeln
127
+ h_file.writeln '#import <Foundation/Foundation.h>'
128
+ h_file.writeln
129
+ h_file.writeln 'extern const struct %s {' % resources_constant_name
130
+ h_file.section do |struct|
131
+ enumerate_sections do |section_key, enumerate_keys|
132
+ struct.writeln 'struct %s {' % section_key
133
+ struct.section do |section_struct|
134
+ enumerate_keys.call do |key, value, comment|
135
+ if documented?
136
+ section_struct.writeln '/// %s' % (comment || value) #unless comment.nil?
137
+ end
138
+ section_struct.writeln '__unsafe_unretained NSString *%s;' % key
139
+ end
140
+ end
141
+ struct.writeln '} %s;' % section_key
142
+ end
143
+ end
144
+ h_file.writeln '} %s;' % resources_constant_name
145
+ end
146
+
147
+ def build_impl_contents m_file
148
+ m_file.writeln BANNER
149
+ m_file.writeln
150
+ m_file.writeln '#import "R.h"'
151
+ m_file.writeln
152
+ m_file.writeln 'const struct %s %s = {' % [resources_constant_name, resources_constant_name]
153
+ m_file.section do |struct|
154
+ enumerate_sections do |section_key, enumerate_keys|
155
+ struct.writeln '.%s = {' % section_key
156
+ struct.section do |section_struct|
157
+ enumerate_keys.call do |key, value|
158
+ section_struct.writeln '.%s = @"%s",' % [key, value]
159
+ end
160
+ end
161
+ struct.writeln '},'
162
+ end
163
+ end
164
+ m_file.writeln '};'
165
+ end
166
+
167
+ def enumerate_sections
168
+ # Iterate sections ordered by key
169
+ for section_key, section_content in @sections.sort
170
+ # Pass section key and block to yield the keys ordered
171
+ proc = Proc.new do |&block|
172
+ for key, value in section_content.sort
173
+ if value.is_a? Hash
174
+ block.call key, value[:value], value[:comment]
175
+ else
176
+ block.call key, value, nil
177
+ end
178
+ end
179
+ end
180
+ yield section_key, proc
181
+ end
182
+ end
183
+
184
+ end
@@ -0,0 +1,31 @@
1
+ class XCRes::StringBuilder
2
+
3
+ attr_accessor :indentation_string
4
+ attr_accessor :result
5
+
6
+ def initialize
7
+ self.indentation_string = ' '
8
+ self.result = ''
9
+ end
10
+
11
+ def << input
12
+ # Only indent string inputs on nested / delegating string builders
13
+ input = self.indentation_string + input unless result.is_a? String
14
+
15
+ self.result << input
16
+ end
17
+
18
+ alias write :<<
19
+
20
+ def writeln input=''
21
+ self << input + "\n"
22
+ end
23
+
24
+ def section &block
25
+ builder = self.class.new
26
+ builder.indentation_string = self.indentation_string
27
+ builder.result = self
28
+ block.call builder
29
+ end
30
+
31
+ end
@@ -0,0 +1,83 @@
1
+ require 'xcres/command/project_command'
2
+ require 'xcres/helper/file_helper'
3
+ require 'xcres/builder/resources_builder'
4
+ require 'xcres/analyzer/aggregate_analyzer'
5
+ require 'xcres/analyzer/resources_aggregate_analyzer'
6
+ require 'xcres/analyzer/strings_analyzer'
7
+
8
+ # The +BuildCommand+ builds the resources index files.
9
+ #
10
+ class XCRes::BuildCommand < XCRes::ProjectCommand
11
+
12
+ include XCRes::FileHelper
13
+
14
+ inherit_parameters!
15
+ parameter '[OUTPUT_PATH]', 'Path where to write to', attribute_name: :output_path
16
+
17
+ def execute
18
+ super
19
+
20
+ # Derive the name for the resources constant file
21
+ self.resources_constant_name ||= derive_resources_constant_name
22
+
23
+ # Locate output path
24
+ self.output_path = locate_output_path
25
+
26
+ build do |builder|
27
+ analyzer = XCRes::AggregateAnalyzer.new(target)
28
+ analyzer.exclude_file_patterns = exclude_file_patterns
29
+ analyzer.logger = logger
30
+ analyzer.add_with_class(XCRes::ResourcesAggregateAnalyzer, shorten_keys: true)
31
+ analyzer.add_with_class(XCRes::StringsAnalyzer, default_language: default_language)
32
+ sections = analyzer.analyze
33
+
34
+ sections.each do |section|
35
+ builder.add_section section.name, section.items, section.options
36
+ end
37
+ end
38
+
39
+ success 'Successfully updated: %s', "#{output_path}.h"
40
+ end
41
+
42
+ def derive_resources_constant_name
43
+ # Fall back to `basename OUTPUT_PATH` or 'R' if both are not given
44
+ if output_path != nil && !File.directory?(output_path)
45
+ basename_without_ext(output_path)
46
+ else
47
+ 'R'
48
+ end
49
+ end
50
+
51
+ def output_dir
52
+ if output_path.nil?
53
+ # Use project dir, if no output path was set
54
+ Pathname(xcodeproj_file_path) + '..'
55
+ else
56
+ path = Pathname(output_path)
57
+ if path.directory?
58
+ path
59
+ else
60
+ path + '..'
61
+ end
62
+ end
63
+ end
64
+
65
+ def locate_output_path
66
+ output_dir.realdirpath + resources_constant_name
67
+ end
68
+
69
+ def build
70
+ # Prepare builder
71
+ builder = XCRes::ResourcesBuilder.new
72
+ builder.output_path = output_path
73
+ builder.logger = logger
74
+ builder.documented = documented?
75
+ builder.resources_constant_name = resources_constant_name
76
+
77
+ yield builder
78
+
79
+ # Write the files, if needed
80
+ builder.build
81
+ end
82
+
83
+ end
@@ -0,0 +1,58 @@
1
+ require 'clamp'
2
+ require 'xcres/logger'
3
+
4
+ # Base class for commands
5
+ #
6
+ class XCRes::Command < Clamp::Command
7
+
8
+ option ['--silent'], :flag, 'Show nothing'
9
+ option ['--[no-]ansi'], :flag, 'Show output without ANSI codes', default: true
10
+ option ['-v', '--verbose'], :flag, 'Show more debugging information'
11
+
12
+ # Run the command, with the specified arguments.
13
+ #
14
+ # This calls {#parse} to process the command-line arguments,
15
+ # then delegates to {#execute}.
16
+ #
17
+ # @param [Array<String>] arguments command-line arguments
18
+ #
19
+ def run(arguments)
20
+ super
21
+ rescue Clamp::HelpWanted => e
22
+ raise e # Clamp will handle this for us
23
+ rescue StandardError => error
24
+ fail error
25
+ exit 1
26
+ end
27
+
28
+ def execute
29
+ # Configure logger
30
+ configure_logger
31
+ end
32
+
33
+ #----------------------------------------------------------------------------#
34
+
35
+ # @!group Logger
36
+
37
+ # Lazy-instantiate a logger
38
+ #
39
+ def logger
40
+ @logger ||= XCRes::Logger.new
41
+ end
42
+
43
+ # Delegate log level methods to the logger
44
+ #
45
+ delegate :inform, :log, :success, :warn, :fail, to: :logger
46
+
47
+ # Checks the configured option to configure the logger
48
+ #
49
+ def configure_logger
50
+ logger.silent = silent?
51
+ logger.colored = ansi?
52
+ if verbose?
53
+ logger.verbose = verbose?
54
+ log 'Verbose mode is enabled.'
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,173 @@
1
+ require 'xcres/command/project_command'
2
+ require 'xcres/command/build_command'
3
+
4
+ # The +InstallCommand+ integrates a build phase to the Xcode project,
5
+ # so that on each build the resources index will be rebuild, if needed.
6
+ #
7
+ class XCRes::InstallCommand < XCRes::ProjectCommand
8
+
9
+ BUILD_PHASE_NAME = 'Build Resource-Index'
10
+
11
+ inherit_parameters!
12
+
13
+ # Execute the command
14
+ #
15
+ # @return [void]
16
+ #
17
+ def execute
18
+ super
19
+
20
+ # Locate the parent group, where the built files will been added to
21
+ parent_group = find_parent_group
22
+
23
+ # Locate the output path
24
+ output_path = parent_group.real_path + 'Resources/R'
25
+
26
+ inform 'Execute build first:'
27
+ build(output_path)
28
+
29
+ integrate!(output_path, parent_group)
30
+
31
+ success 'Successfully integrated into %s', project_path
32
+ end
33
+
34
+ # Find parent group, where the built files will been added to.
35
+ # It will return the first group, which was found of the following list.
36
+ # * 'Supporting Files' group
37
+ # * target-specific group
38
+ # * main group
39
+ #
40
+ # @raise [ArgumentError]
41
+ # if no main group exists, which means that the project is invalid
42
+ #
43
+ # @return [PBXGroup]
44
+ #
45
+ def find_parent_group
46
+ # Get main group and ensure that it exists
47
+ main_group = project.main_group
48
+ raise ArgumentError, "Didn't found main group" if main_group.nil?
49
+
50
+ # Get target-specific group, if the default project layout is in use
51
+ src_group = main_group.groups.find { |g| g.path == target.name }
52
+ if src_group != nil
53
+ log "Found target group, will use its path as base output path."
54
+ else
55
+ log "Didn't found target group, expected a group with path '#{target.name}'."
56
+ end
57
+
58
+ # Find 'Supporting Files' group
59
+ groups = main_group.recursive_children_groups
60
+ support_files_group = groups.find { |g| g.name == 'Supporting Files' }
61
+ warn "Didn't found support files group" if support_files_group.nil?
62
+
63
+ support_files_group || src_group || main_group
64
+ end
65
+
66
+ # Trigger a build for the current project
67
+ #
68
+ # @param [Pathname] output_path
69
+ # the argument OUTPUT_PATH for the build subcommand
70
+ #
71
+ # @return [void]
72
+ #
73
+ def build(output_path)
74
+ build_cmd = XCRes::BuildCommand.new("#{invocation_path} build", context, attribute_values)
75
+ build_cmd.logger.indentation = ' '
76
+ build_cmd.run([project_path.to_s, output_path.relative_path_from(Pathname.pwd).to_s])
77
+ end
78
+
79
+ # Integrate the build phase and add the built files to the project
80
+ #
81
+ # @param [Pathname] output_path
82
+ # the argument OUTPUT_PATH for the build subcommand
83
+ #
84
+ # @param [PBXGroup] parent_group
85
+ # the group where to integrate
86
+ #
87
+ # @return [void]
88
+ #
89
+ def integrate!(output_path, parent_group)
90
+ # Find or create shell script build phase
91
+ build_phase = target.shell_script_build_phases.find do |bp|
92
+ bp.name == BUILD_PHASE_NAME
93
+ end
94
+ build_phase ||= target.new_shell_script_build_phase(BUILD_PHASE_NAME)
95
+
96
+ # Remove build phase to re-insert before compile sources
97
+ target.build_phases.delete(build_phase)
98
+ index = target.build_phases.index(target.source_build_phase)
99
+ target.build_phases.insert(index, build_phase)
100
+
101
+ # Set shell script
102
+ script_output_path = output_path.relative_path_from(src_root_path)
103
+ build_phase.shell_script = "xcres --no-ansi build $PROJECT_FILE_PATH $SRCROOT/#{script_output_path}\n"
104
+
105
+ # Find or create 'Resources' group in 'Supporting Files'
106
+ res_group = parent_group.groups.find { |g| g.name == 'Resources' }
107
+ res_group ||= parent_group.new_group('Resources', Pathname('Resources'))
108
+
109
+ # Find or create references to resources index files
110
+ h_file = res_group.find_file_by_path('R.h') || res_group.new_file('R.h')
111
+ m_file = res_group.find_file_by_path('R.m') || res_group.new_file('R.m')
112
+
113
+ # Add .m file to source build phase, if it doesn't not already exist there
114
+ target.source_build_phase.add_file_reference(m_file, true)
115
+
116
+ # Add .h file to prefix header
117
+ prefix_headers.each do |path|
118
+ realpath = src_root_path + path
119
+ next unless File.exist?(realpath)
120
+ File.open(realpath, 'a+') do |f|
121
+ import_snippet = "#import \"#{h_file.path}\"\n"
122
+ unless f.readlines.include?(import_snippet)
123
+ f.write "\n#{import_snippet}"
124
+ end
125
+ end
126
+ end
127
+
128
+ project.save()
129
+ end
130
+
131
+ # Return a relative path to the project
132
+ #
133
+ # @return [Pathname]
134
+ #
135
+ def project_path
136
+ project.path.relative_path_from(Pathname.pwd)
137
+ end
138
+
139
+ # Return the path, which would be represented by the value of the
140
+ # build setting `$SRCROOT`.
141
+ #
142
+ # @return [Pathname]
143
+ #
144
+ def src_root_path
145
+ project_path.realpath + '..'
146
+ end
147
+
148
+ # Return a hash of attribute values
149
+ #
150
+ # @return [Hash{Clamp::Attribute::Definition => #to_s}]
151
+ #
152
+ def attribute_values
153
+ attribute_values = {}
154
+ self.class.recognised_options.each do |attribute|
155
+ if attribute.of(self).defined?
156
+ attribute_values[attribute] = attribute.of(self).get
157
+ end
158
+ end
159
+ attribute_values
160
+ end
161
+
162
+ # Discover prefix header by build settings of the application target
163
+ #
164
+ # @return [Set<Pathname>]
165
+ # the relative paths to the .pch files
166
+ #
167
+ def prefix_headers
168
+ @prefix_headers ||= target.build_configurations.map do |config|
169
+ Pathname(config.build_settings['GCC_PREFIX_HEADER'])
170
+ end.flatten.to_set
171
+ end
172
+
173
+ end
@@ -0,0 +1,14 @@
1
+ require 'xcodeproj'
2
+ require 'xcres/logger'
3
+ require 'xcres/command/command'
4
+ require 'xcres/command/build_command'
5
+ require 'xcres/command/install_command'
6
+ require 'xcres/command/version_command'
7
+
8
+ class XCRes::MainCommand < XCRes::Command
9
+
10
+ subcommand 'build', 'Build the resources index files', XCRes::BuildCommand
11
+ subcommand 'install', 'Install a build phase into the project', XCRes::InstallCommand
12
+ subcommand 'version', 'Show the gem version', XCRes::VersionCommand
13
+
14
+ end
@@ -0,0 +1,111 @@
1
+ require 'xcres/command/command'
2
+ require 'xcodeproj'
3
+
4
+ # The +ProjectCommand+ is the base class for commands,
5
+ # which analyze or modify Xcode projects.
6
+ #
7
+ class XCRes::ProjectCommand < XCRes::Command
8
+
9
+ option ['--[no-]documented'], :flag, 'Add documentation to the generated files', default: true
10
+ #option ['-d', '--dry-run'], :flag, 'Does nothing on the file system'
11
+
12
+ option ['-t', '--target'], 'TARGET', 'Application target to use', attribute_name: :target_name
13
+ option ['-x', '--exclude'], 'FILE_PATTERN', 'File pattern which should be excluded (default: ["InfoPlist.strings"])', multivalued: true, attribute_name: :exclude_file_patterns, default: ['InfoPlist.strings']
14
+ option ['-n', '--name'], 'NAME', 'Name of the resources constant (default: `basename OUTPUT_PATH`)', attribute_name: :resources_constant_name
15
+ option ['-l', '--language'], 'LANGUAGE', 'Default language to build the keys', attribute_name: :default_language do |language|
16
+ raise ArgumentError.new 'Expected a two-letter code conforming ISO 639-1 as LANGUAGE' unless String(language).length == 2
17
+ language
18
+ end
19
+
20
+ # Define parameter in an inheritable way
21
+ #
22
+ def self.inherit_parameters!
23
+ parameter '[XCODEPROJ]', 'Xcode project file to inspect (automatically located on base of the current directory if not given)', attribute_name: :xcodeproj_file_path
24
+ end
25
+
26
+
27
+ def execute
28
+ super
29
+
30
+ # Try to discover Xcode project at given path.
31
+ self.xcodeproj_file_path = find_xcodeproj
32
+ end
33
+
34
+
35
+ #----------------------------------------------------------------------------#
36
+
37
+ # @!group Xcode Project
38
+
39
+ # Opens the Xcode project, if not already opened
40
+ #
41
+ # @return [Xcodeproj::Project]
42
+ # the Xcode project
43
+ #
44
+ def project
45
+ @project ||= Xcodeproj::Project.open(xcodeproj_file_path)
46
+ end
47
+
48
+ # Find the application target to use
49
+ #
50
+ # @return [PBXNativeTarget]
51
+ #
52
+ def target
53
+ if target_name != nil
54
+ application_targets.find { |t| t.name == target }
55
+ else
56
+ if application_targets.count == 1
57
+ application_targets.first
58
+ else
59
+ raise ArgumentError.new 'Multiple application target in project. ' \
60
+ 'Please select one by specifying the option `--target TARGET`.'
61
+ end
62
+ end
63
+ end
64
+
65
+ # Find all application targets in the project
66
+ #
67
+ # @return [Array<PBXNativeTarget>]
68
+ #
69
+ def application_targets
70
+ @application_targets ||= project.targets.select do |target|
71
+ target.is_a?(Xcodeproj::Project::Object::PBXNativeTarget) \
72
+ && target.product_type == Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application]
73
+ end
74
+ end
75
+
76
+ def find_xcodeproj
77
+ path = discover_xcodeproj_file_path!
78
+
79
+ if !Dir.exist?(path) || !File.exist?(path + '/project.pbxproj')
80
+ raise ArgumentError.new 'XCODEPROJ at %s was not found or is not a ' \
81
+ 'valid Xcode project.' % path
82
+ end
83
+
84
+ success 'Use %s as XCODEPROJ.', path
85
+
86
+ return path
87
+ end
88
+
89
+ def discover_xcodeproj_file_path!
90
+ if xcodeproj_file_path.nil?
91
+ warn 'Argument XCODEPROJ is not set. Use the current directory.'
92
+ discover_xcodeproj_file_path_in_dir! '.'
93
+ elsif Dir.exist?(xcodeproj_file_path) && !File.fnmatch('*.xcodeproj', xcodeproj_file_path)
94
+ warn 'Argument XCODEPROJ is a directory. ' \
95
+ 'Try to locate the Xcode project in this directory.'
96
+ discover_xcodeproj_file_path_in_dir! xcodeproj_file_path
97
+ else
98
+ xcodeproj_file_path
99
+ end
100
+ end
101
+
102
+ def discover_xcodeproj_file_path_in_dir! dir
103
+ xcodeproj_file_paths = Dir[dir + '/*.xcodeproj']
104
+ if xcodeproj_file_paths.count == 0
105
+ raise ArgumentError.new 'Argument XCODEPROJ was not given and no ' \
106
+ '*.xcodeproj was found in current directory.'
107
+ end
108
+ xcodeproj_file_paths.first
109
+ end
110
+
111
+ end
@@ -0,0 +1,12 @@
1
+ require 'xcres/command/command'
2
+
3
+ # The +VersionCommand+ prints the gem version.
4
+ #
5
+ class XCRes::VersionCommand < XCRes::Command
6
+
7
+ def execute
8
+ super
9
+ inform XCRes::VERSION
10
+ end
11
+
12
+ end
@@ -0,0 +1,16 @@
1
+ module XCRes
2
+ module FileHelper
3
+
4
+ # Return the basename without its extname
5
+ # e.g: 'dir/test.jpg' => 'test'
6
+ #
7
+ # @param [String] file_path
8
+ #
9
+ # @return [String]
10
+ #
11
+ def basename_without_ext file_path
12
+ File.basename file_path, File.extname(file_path)
13
+ end
14
+
15
+ end
16
+ end