xcres 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +12 -9
  3. data/README.md +43 -5
  4. data/lib/xcres/analyzer/strings_analyzer.rb +1 -1
  5. data/lib/xcres/builder/resources_builder.rb +77 -12
  6. data/lib/xcres/command/build_command.rb +6 -1
  7. data/lib/xcres/command/install_command.rb +23 -16
  8. data/lib/xcres/command/project_command.rb +1 -0
  9. data/lib/xcres/version.rb +1 -1
  10. data/spec/fixtures/Example/Example/en.lproj/Localizable.strings +1 -0
  11. data/spec/integration.rb +8 -0
  12. data/spec/integration/build-keyword-clash/after/R.h +1 -3
  13. data/spec/integration/build-keyword-clash/after/R.m +0 -2
  14. data/spec/integration/build-swift/after/Example/Example.xcodeproj.yaml +168 -0
  15. data/spec/integration/build-swift/after/Example/Example/AppDelegate.h +15 -0
  16. data/spec/integration/build-swift/after/Example/Example/AppDelegate.m +49 -0
  17. data/spec/integration/build-swift/after/Example/Example/Example-Info.plist +38 -0
  18. data/spec/integration/build-swift/after/Example/Example/Example-Prefix.pch +16 -0
  19. data/spec/integration/build-swift/after/Example/Example/Icons.bundle/tab_bar/tabbar_list.png +0 -0
  20. data/spec/integration/build-swift/after/Example/Example/Icons.bundle/tab_bar/tabbar_list@2x.png +0 -0
  21. data/spec/integration/build-swift/after/Example/Example/Icons.bundle/tab_bar/tabbar_map.png +0 -0
  22. data/spec/integration/build-swift/after/Example/Example/Icons.bundle/tab_bar/tabbar_map@2x.png +0 -0
  23. data/spec/integration/build-swift/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +28 -0
  24. data/spec/integration/build-swift/after/Example/Example/Images.xcassets/Cats/GrumpyCat.imageset/Contents.json +23 -0
  25. data/spec/integration/build-swift/after/Example/Example/Images.xcassets/Cats/GrumpyCat.imageset/GrumpyCat.jpg +0 -0
  26. data/spec/integration/build-swift/after/Example/Example/Images.xcassets/Cats/GrumpyCat.imageset/GrumpyCat@2x.jpg +0 -0
  27. data/spec/integration/build-swift/after/Example/Example/Images.xcassets/Cats/GrumpyCat.imageset/GrumpyCat@3x.jpg +0 -0
  28. data/spec/integration/build-swift/after/Example/Example/Images.xcassets/Doge.imageset/Contents.json +22 -0
  29. data/spec/integration/build-swift/after/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
  30. data/spec/integration/build-swift/after/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
  31. data/spec/integration/build-swift/after/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  32. data/spec/integration/build-swift/after/Example/Example/Images/doge.jpeg +0 -0
  33. data/spec/integration/build-swift/after/Example/Example/Images/nyanCat.png +0 -0
  34. data/spec/integration/build-swift/after/Example/Example/de.lproj/Localizable.strings +12 -0
  35. data/spec/integration/build-swift/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
  36. data/spec/integration/build-swift/after/Example/Example/en.lproj/Localizable.strings +15 -0
  37. data/spec/integration/build-swift/after/Example/Example/main.m +18 -0
  38. data/spec/integration/build-swift/after/R.swift +47 -0
  39. data/spec/integration/build-swift/after/execution_output.txt +19 -0
  40. data/spec/integration/build-swift/before/Example/Example.xcodeproj/project.pbxproj +453 -0
  41. data/spec/integration/build-swift/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  42. data/spec/integration/build-swift/before/Example/Example/AppDelegate.h +15 -0
  43. data/spec/integration/build-swift/before/Example/Example/AppDelegate.m +49 -0
  44. data/spec/integration/build-swift/before/Example/Example/Example-Info.plist +38 -0
  45. data/spec/integration/build-swift/before/Example/Example/Example-Prefix.pch +16 -0
  46. data/spec/integration/build-swift/before/Example/Example/Icons.bundle/tab_bar/tabbar_list.png +0 -0
  47. data/spec/integration/build-swift/before/Example/Example/Icons.bundle/tab_bar/tabbar_list@2x.png +0 -0
  48. data/spec/integration/build-swift/before/Example/Example/Icons.bundle/tab_bar/tabbar_map.png +0 -0
  49. data/spec/integration/build-swift/before/Example/Example/Icons.bundle/tab_bar/tabbar_map@2x.png +0 -0
  50. data/spec/integration/build-swift/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +28 -0
  51. data/spec/integration/build-swift/before/Example/Example/Images.xcassets/Cats/GrumpyCat.imageset/Contents.json +23 -0
  52. data/spec/integration/build-swift/before/Example/Example/Images.xcassets/Cats/GrumpyCat.imageset/GrumpyCat.jpg +0 -0
  53. data/spec/integration/build-swift/before/Example/Example/Images.xcassets/Cats/GrumpyCat.imageset/GrumpyCat@2x.jpg +0 -0
  54. data/spec/integration/build-swift/before/Example/Example/Images.xcassets/Cats/GrumpyCat.imageset/GrumpyCat@3x.jpg +0 -0
  55. data/spec/integration/build-swift/before/Example/Example/Images.xcassets/Doge.imageset/Contents.json +22 -0
  56. data/spec/integration/build-swift/before/Example/Example/Images.xcassets/Doge.imageset/doge.png +0 -0
  57. data/spec/integration/build-swift/before/Example/Example/Images.xcassets/Doge.imageset/doge@2x.png +0 -0
  58. data/spec/integration/build-swift/before/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  59. data/spec/integration/build-swift/before/Example/Example/Images/doge.jpeg +0 -0
  60. data/spec/integration/build-swift/before/Example/Example/Images/nyanCat.png +0 -0
  61. data/spec/integration/build-swift/before/Example/Example/de.lproj/Localizable.strings +12 -0
  62. data/spec/integration/build-swift/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
  63. data/spec/integration/build-swift/before/Example/Example/en.lproj/Localizable.strings +15 -0
  64. data/spec/integration/build-swift/before/Example/Example/main.m +18 -0
  65. data/spec/integration/build-var-infoplist/after/R.h +1 -1
  66. data/spec/integration/build/after/R.h +1 -1
  67. data/spec/integration/install-again/after/Example/Example.xcodeproj.yaml +1 -1
  68. data/spec/integration/install-again/after/Example/Example/Resources/R.h +1 -3
  69. data/spec/integration/install-again/after/Example/Example/Resources/R.m +0 -2
  70. data/spec/integration/install-again/after/execution_output.txt +0 -1
  71. data/spec/integration/install-again/before/Example/Example/Resources/R.h +1 -1
  72. data/spec/integration/install-again/before/Example/Example/Resources/R.m +0 -2
  73. data/spec/integration/install-moved-supporting-files/after/Example/Example.xcodeproj.yaml +1 -1
  74. data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/Resources/R.h +1 -3
  75. data/spec/integration/install-moved-supporting-files/after/Example/Supporting_Files/Resources/R.m +0 -2
  76. data/spec/integration/install-no-supporting-files/after/Example/Example.xcodeproj.yaml +1 -1
  77. data/spec/integration/install-no-supporting-files/after/Example/Resources/R.h +1 -3
  78. data/spec/integration/install-no-supporting-files/after/Example/Resources/R.m +0 -2
  79. data/spec/integration/install-swift/after/Example/Example.xcodeproj.yaml +171 -0
  80. data/spec/integration/install-swift/after/Example/Example.xcodeproj/project.pbxproj +898 -0
  81. data/spec/integration/install-swift/after/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  82. data/spec/integration/install-swift/after/Example/Example/AppDelegate.h +15 -0
  83. data/spec/integration/install-swift/after/Example/Example/AppDelegate.m +49 -0
  84. data/spec/integration/install-swift/after/Example/Example/Example-Info.plist +38 -0
  85. data/spec/integration/install-swift/after/Example/Example/Example-Prefix.pch +16 -0
  86. data/spec/integration/install-swift/after/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  87. data/spec/integration/install-swift/after/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  88. data/spec/integration/install-swift/after/Example/Example/Resources/R.swift +23 -0
  89. data/spec/integration/install-swift/after/Example/Example/en.lproj/InfoPlist.strings +2 -0
  90. data/spec/integration/install-swift/after/Example/Example/main.m +18 -0
  91. data/spec/integration/install-swift/after/execution_output.txt +22 -0
  92. data/spec/integration/install-swift/before/Example/Example.xcodeproj/project.pbxproj +421 -0
  93. data/spec/integration/install-swift/before/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  94. data/spec/integration/install-swift/before/Example/Example/AppDelegate.h +15 -0
  95. data/spec/integration/install-swift/before/Example/Example/AppDelegate.m +49 -0
  96. data/spec/integration/install-swift/before/Example/Example/Example-Info.plist +38 -0
  97. data/spec/integration/install-swift/before/Example/Example/Example-Prefix.pch +16 -0
  98. data/spec/integration/install-swift/before/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  99. data/spec/integration/install-swift/before/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  100. data/spec/integration/install-swift/before/Example/Example/en.lproj/InfoPlist.strings +2 -0
  101. data/spec/integration/install-swift/before/Example/Example/main.m +18 -0
  102. data/spec/integration/install/after/Example/Example.xcodeproj.yaml +1 -1
  103. data/spec/integration/install/after/Example/Example/Resources/R.h +1 -3
  104. data/spec/integration/install/after/Example/Example/Resources/R.m +0 -2
  105. data/spec/integration/version/after/execution_output.txt +1 -1
  106. data/spec/unit/analyzer/strings_analyzer_spec.rb +1 -0
  107. data/spec/unit/builder/resources_builder_spec.rb +43 -4
  108. data/xcres.gemspec +0 -1
  109. metadata +151 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 66662fa71e28ebba0f9e8709d34eaa747884acd5
4
- data.tar.gz: 848102aa3b625215e7523bfec8e216e6c9d2b80f
3
+ metadata.gz: 07f166368a1c3c20e976d5cb5dac003e1f0b0e87
4
+ data.tar.gz: 164c9556d5bbf9054c05cd869e349219bd615e64
5
5
  SHA512:
6
- metadata.gz: 22ab34d31c641dfae88fe78ef6e5c19e9a60e6b1244f269f511343b7a6f72461640c7cf8d6b845b414dba357a27a981c85de16a42879dfa69bcd7804fc790467
7
- data.tar.gz: 477d6500c3aa810f1d97f04203e00965cbe0ab11b2c9f2977a5ccaecc090d9c2250a721da0e009298bf32fb3a3bc5adce0ea82eefde001abfd5f2df8cbe5c475
6
+ metadata.gz: ee5805f7a5e36fc235ae813606a5bb738eb19a9ad89f6ccaf578e1996158470e5f76b49f210e25dd80635087af7810aa146df365f85cc8b59d160a7fff992380
7
+ data.tar.gz: f0db23ce61854cbd8ad7095e5884ef057f5031c3524ec1dde941d675fb316cd1ef9f678b92e667add56c6e112c98e40ddc1768ae5ceab5c249d4124a3a38764a
data/Gemfile.lock CHANGED
@@ -1,42 +1,41 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- xcres (0.4.4)
4
+ xcres (0.5.0)
5
5
  activesupport (>= 3.2.15, < 4)
6
6
  clamp (~> 0.6.3)
7
7
  colored (~> 1.2)
8
- libxml-ruby
9
8
  xcodeproj (~> 0.18)
10
9
 
11
10
  GEM
12
11
  remote: https://rubygems.org/
13
12
  specs:
14
- activesupport (3.2.19)
13
+ activesupport (3.2.22)
15
14
  i18n (~> 0.6, >= 0.6.4)
16
15
  multi_json (~> 1.0)
17
16
  ast (2.0.0)
18
17
  bacon (1.2.0)
19
- clamp (0.6.3)
18
+ claide (0.9.1)
19
+ clamp (0.6.5)
20
20
  clintegracon (0.5.2)
21
21
  colored (~> 1.2)
22
22
  diffy
23
23
  coderay (1.1.0)
24
24
  colored (1.2)
25
25
  diffy (3.0.6)
26
- i18n (0.6.11)
26
+ i18n (0.7.0)
27
27
  inch (0.4.10)
28
28
  pry
29
29
  sparkr (>= 0.2.0)
30
30
  term-ansicolor
31
31
  yard (~> 0.8.7)
32
- libxml-ruby (2.7.0)
33
32
  metaclass (0.0.4)
34
33
  method_source (0.8.2)
35
34
  mocha (1.1.0)
36
35
  metaclass (~> 0.0.1)
37
36
  mocha-on-bacon (0.2.2)
38
37
  mocha (>= 0.13.0)
39
- multi_json (1.10.1)
38
+ multi_json (1.11.2)
40
39
  parser (2.2.0.pre.4)
41
40
  ast (>= 1.1, < 3.0)
42
41
  slop (~> 3.4, >= 3.4.5)
@@ -61,8 +60,9 @@ GEM
61
60
  term-ansicolor (1.3.0)
62
61
  tins (~> 1.0)
63
62
  tins (1.3.2)
64
- xcodeproj (0.19.4)
65
- activesupport (~> 3.0)
63
+ xcodeproj (0.28.2)
64
+ activesupport (>= 3)
65
+ claide (~> 0.9.1)
66
66
  colored (~> 1.2)
67
67
  yard (0.8.7.4)
68
68
 
@@ -81,3 +81,6 @@ DEPENDENCIES
81
81
  rake
82
82
  rubocop
83
83
  xcres!
84
+
85
+ BUNDLED WITH
86
+ 1.10.6
data/README.md CHANGED
@@ -26,18 +26,43 @@ capitalization or converting name scheme from *train-case* or *snake_case* to
26
26
  *camelCase* and vice versa.
27
27
 
28
28
  It will warn you in Xcode on build, if certain resources or string keys can't be
29
- references, because their name contain invalid chars, duplicates in the
29
+ referenced, because their name contain invalid chars, duplicates in the
30
30
  *camelCase* variant with another key, or would be equal to a protected compiler
31
31
  keyword.
32
32
 
33
33
  The generated index could look like below.
34
34
 
35
- While this is still **Objective-C**, `xcres` is compatible with **Swift**.
36
- All you need to do is to add an import to the generated header to your
37
- project's bridging header.
35
+ `xcres` can generate code both as **Swift** or **Objective-C**.
36
+ If you are using both in your project choose **Objective-C** and add an import to
37
+ the generated header to your project's bridging header.
38
38
 
39
+ **Swift**
40
+ ```swift
41
+ public class R {
42
+ public enum Images: String {
43
+ /// doge.jpeg
44
+ case doge = "doge.jpeg"
45
+ }
46
+ public enum ImagesAssets: String {
47
+ /// AppIcon
48
+ case app = "AppIcon"
49
+ /// LaunchImage
50
+ case launch = "LaunchImage"
51
+ /// DefaultAvatar
52
+ case defaultAvatar = "DefaultAvatar"
53
+ }
54
+ public enum Strings: String {
55
+ /// Title shown if a wrong password was entered.
56
+ case errorTitleWrongPassword = "error_title_wrong_password"
57
+ /// Message shown if a wrong password was entered.
58
+ case errorMessageWrongPassword = "error_message_wrong_password"
59
+ }
60
+ }
61
+ ```
62
+
63
+ **Objective-C**
39
64
  ```objc
40
- const struct R {
65
+ FOUNDATION_EXTERN const struct R {
41
66
  struct Images {
42
67
  /// doge.jpeg
43
68
  __unsafe_unretained NSString *doge;
@@ -78,6 +103,12 @@ $ [sudo] gem install xcres
78
103
  Use the automatic integration to add a build phase to your project,
79
104
  by executing the following command:
80
105
 
106
+ **Swift**
107
+ ```bash
108
+ $ xcres install --swift
109
+ ```
110
+
111
+ **Objective-C**
81
112
  ```bash
82
113
  $ xcres install
83
114
  ```
@@ -145,6 +176,12 @@ NSLocalizedString(@"error_message_wrong_password", @"Message shown if a wrong pa
145
176
 
146
177
  Just write:
147
178
 
179
+ **Swift**
180
+ ```swift
181
+ R.Strings.errorMessageWrongPassword.localizedValue
182
+ ```
183
+
184
+ **Objective-C**
148
185
  ```objc
149
186
  NSLocalizedString(R.Strings.errorMessageWrongPassword, @"Message shown if a wrong password was entered.")
150
187
  ```
@@ -179,6 +216,7 @@ your project to non-natural language keys.
179
216
  ## Credits
180
217
 
181
218
  The logo was designed by [@kuchengnom](https://github.com/kuchengnom).
219
+ Swift support was implemented by [@timbodeit](https://github.com/timbodeit).
182
220
 
183
221
 
184
222
  ## License
@@ -233,7 +233,7 @@ module XCRes
233
233
  strings = read_strings_file(path)
234
234
 
235
235
  # Reject generated identifiers used by Interface Builder
236
- strings.reject! { |key, _| /^[a-zA-Z0-9]{3}(-[a-zA-Z0-9]{3}){2}/.match(key) }
236
+ strings.reject! { |key, _| /^[a-zA-Z0-9]{3}-[a-zA-Z0-9]{2,3}-[a-zA-Z0-9]{3}/.match(key) }
237
237
 
238
238
  keys = Hash[strings.map do |key, value|
239
239
  [key, { value: key, comment: value.gsub(/[\r\n]/, ' ') }]
@@ -13,12 +13,29 @@ class XCRes::ResourcesBuilder < XCRes::FileBuilder
13
13
  //
14
14
  EOS
15
15
 
16
- COMPILER_KEYWORDS = %w{
16
+ OBJC_COMPILER_KEYWORDS = %w{
17
17
  auto break case char const continue default do double else enum extern float
18
18
  for goto if inline int long register restrict return short signed sizeof
19
19
  static struct switch typedef union unsigned void volatile while
20
20
  }
21
21
 
22
+ SWIFT_COMPILER_KEYWORDS = %w{
23
+ class deinit enum extension func import init internal let operator private
24
+ protocol public static struct subscript typealias var break case continue
25
+ default do else fallthrough for if in return switch where while as
26
+ dynamicType false is nil self Self super true
27
+ }
28
+
29
+ SWIFT_EXTENSIONS = <<EOS
30
+ public extension %s.Strings {
31
+ public var localizedValue: String {
32
+ return NSLocalizedString(self.rawValue,
33
+ bundle: NSBundle(forClass: R.self),
34
+ comment: "")
35
+ }
36
+ }
37
+ EOS
38
+
22
39
  # @return [String]
23
40
  # the name of the constant in the generated file(s)
24
41
  attr_accessor :resources_constant_name
@@ -29,6 +46,12 @@ EOS
29
46
  attr_accessor :documented
30
47
  alias :documented? :documented
31
48
 
49
+ # @return [Bool]
50
+ # whether Swift code should be generated,
51
+ # Objective-C used if false, false by default
52
+ attr_accessor :swift
53
+ alias :swift? :swift
54
+
32
55
  # @return [Hash{String => {String => String}}]
33
56
  # the sections, which will been written to the built files
34
57
  attr_reader :sections
@@ -38,6 +61,7 @@ EOS
38
61
  def initialize
39
62
  @sections = {}
40
63
  self.documented = true
64
+ self.swift = false
41
65
  end
42
66
 
43
67
  # Extract resource name from #output_path, if not customized
@@ -63,7 +87,8 @@ EOS
63
87
  end
64
88
 
65
89
  # Skip compiler keywords
66
- if COMPILER_KEYWORDS.include? transformed_key
90
+ compiler_keywords = swift? ? SWIFT_COMPILER_KEYWORDS : OBJC_COMPILER_KEYWORDS
91
+ if compiler_keywords.include? transformed_key
67
92
  logger.warn "Skip invalid key: '%s'. (Was transformed to keyword '%s')", key, transformed_key
68
93
  next
69
94
  end
@@ -77,14 +102,11 @@ EOS
77
102
  def build
78
103
  super
79
104
 
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)
105
+ if swift?
106
+ build_and_write_swift
107
+ else
108
+ build_and_write_objc
109
+ end
88
110
  end
89
111
 
90
112
  protected
@@ -118,7 +140,26 @@ EOS
118
140
  end
119
141
  end
120
142
 
121
- result
143
+ # If the first character is not a letter, prefix it with an underscore
144
+ result.gsub(/^[^_a-z]/i, '_\0')
145
+ end
146
+
147
+ def build_and_write_swift
148
+ # Build file contents and write them to disk
149
+ write_file_eventually "#{output_path}.swift", (build_contents do |swift_file|
150
+ build_swift_contents swift_file
151
+ end)
152
+ end
153
+
154
+ def build_and_write_objc
155
+ # Build file contents and write them to disk
156
+ write_file_eventually "#{output_path}.h", (build_contents do |h_file|
157
+ build_header_contents h_file
158
+ end)
159
+
160
+ write_file_eventually "#{output_path}.m", (build_contents do |m_file|
161
+ build_impl_contents m_file
162
+ end)
122
163
  end
123
164
 
124
165
  def build_header_contents h_file
@@ -126,7 +167,7 @@ EOS
126
167
  h_file.writeln
127
168
  h_file.writeln '#import <Foundation/Foundation.h>'
128
169
  h_file.writeln
129
- h_file.writeln 'extern const struct %s {' % resources_constant_name
170
+ h_file.writeln 'FOUNDATION_EXTERN const struct %s {' % resources_constant_name
130
171
  h_file.section do |struct|
131
172
  enumerate_sections do |section_key, enumerate_keys|
132
173
  struct.writeln 'struct %s {' % section_key
@@ -164,9 +205,33 @@ EOS
164
205
  m_file.writeln '};'
165
206
  end
166
207
 
208
+ def build_swift_contents swift_file
209
+ swift_file.writeln BANNER
210
+ swift_file.writeln 'public class %s {' % resources_constant_name
211
+ swift_file.section do |struct|
212
+ enumerate_sections do |section_key, enumerate_keys|
213
+ struct.writeln 'public enum %s: String {' % section_key
214
+ struct.section do |section_struct|
215
+ enumerate_keys.call do |key, value, comment|
216
+ if documented?
217
+ section_struct.writeln '/// %s' % (comment || value) #unless comment.nil?
218
+ end
219
+ section_struct.writeln 'case %s = "%s"' % [key, value]
220
+ end
221
+ end
222
+ struct.writeln '}'
223
+ end
224
+ end
225
+ swift_file.writeln '}'
226
+ swift_file.writeln
227
+ swift_file.writeln SWIFT_EXTENSIONS % resources_constant_name
228
+ end
229
+
167
230
  def enumerate_sections
168
231
  # Iterate sections ordered by key
169
232
  for section_key, section_content in @sections.sort
233
+ next if section_content.length == 0
234
+
170
235
  # Pass section key and block to yield the keys ordered
171
236
  proc = Proc.new do |&block|
172
237
  for key, value in section_content.sort
@@ -36,7 +36,11 @@ class XCRes::BuildCommand < XCRes::ProjectCommand
36
36
  end
37
37
  end
38
38
 
39
- success 'Successfully updated: %s', "#{output_path}.h"
39
+ if swift?
40
+ success 'Successfully updated: %s', "#{output_path}.swift"
41
+ else
42
+ success 'Successfully updated: %s', "#{output_path}.h"
43
+ end
40
44
  end
41
45
 
42
46
  def derive_resources_constant_name
@@ -72,6 +76,7 @@ class XCRes::BuildCommand < XCRes::ProjectCommand
72
76
  builder.output_path = output_path
73
77
  builder.logger = logger
74
78
  builder.documented = documented?
79
+ builder.swift = swift?
75
80
  builder.resources_constant_name = resources_constant_name
76
81
 
77
82
  yield builder
@@ -100,28 +100,35 @@ class XCRes::InstallCommand < XCRes::ProjectCommand
100
100
 
101
101
  # Set shell script
102
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"
103
+ documented_argument = documented? ? "--documented" : "--no-documented"
104
+ swift_argument = swift? ? "--swift" : "--no-swift"
105
+ build_phase.shell_script = "xcres --no-ansi build #{documented_argument} #{swift_argument} $PROJECT_FILE_PATH $SRCROOT/#{script_output_path}\n"
104
106
  build_phase.show_env_vars_in_log = '0'
105
107
 
106
108
  # Find or create 'Resources' group in 'Supporting Files'
107
109
  res_group = parent_group.groups.find { |g| g.name == 'Resources' }
108
110
  res_group ||= parent_group.new_group('Resources', Pathname('Resources'))
109
111
 
110
- # Find or create references to resources index files
111
- h_file = res_group.find_file_by_path('R.h') || res_group.new_file('R.h')
112
- m_file = res_group.find_file_by_path('R.m') || res_group.new_file('R.m')
113
-
114
- # Add .m file to source build phase, if it doesn't not already exist there
115
- target.source_build_phase.add_file_reference(m_file, true)
116
-
117
- # Add .h file to prefix header
118
- prefix_headers.each do |path|
119
- realpath = src_root_path + path
120
- next unless File.exist?(realpath)
121
- File.open(realpath, 'a+') do |f|
122
- import_snippet = "#import \"#{h_file.path}\"\n"
123
- unless f.readlines.include?(import_snippet)
124
- f.write "\n#{import_snippet}"
112
+ if swift?
113
+ # Find or create references to resources index files
114
+ swift_file = res_group.find_file_by_path('R.swift') || res_group.new_file('R.swift')
115
+ # Add .swift file to source build phase, if it doesn't not already exist there
116
+ target.source_build_phase.add_file_reference(swift_file, true)
117
+ else
118
+ # Find or create references to resources index files
119
+ h_file = res_group.find_file_by_path('R.h') || res_group.new_file('R.h')
120
+ m_file = res_group.find_file_by_path('R.m') || res_group.new_file('R.m')
121
+ # Add .m file to source build phase, if it doesn't not already exist there
122
+ target.source_build_phase.add_file_reference(m_file, true)
123
+ # Add .h file to prefix header
124
+ prefix_headers.each do |path|
125
+ realpath = src_root_path + path
126
+ next unless File.exist?(realpath)
127
+ File.open(realpath, 'a+') do |f|
128
+ import_snippet = "#import \"#{h_file.path}\"\n"
129
+ unless f.readlines.include?(import_snippet)
130
+ f.write "\n#{import_snippet}"
131
+ end
125
132
  end
126
133
  end
127
134
  end
@@ -9,6 +9,7 @@ class XCRes::ProjectCommand < XCRes::Command
9
9
  option ['--[no-]documented'], :flag, 'Add documentation to the generated files', default: true
10
10
  #option ['-d', '--dry-run'], :flag, 'Does nothing on the file system'
11
11
 
12
+ option ['--[no-]swift'], :flag, 'Generate file as Swift code', default: false
12
13
  option ['-t', '--target'], 'TARGET', 'Target to search & analyze', attribute_name: :target_name
13
14
  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
15
  option ['-n', '--name'], 'NAME', 'Name of the resources constant (default: `basename OUTPUT_PATH`)', attribute_name: :resources_constant_name
data/lib/xcres/version.rb CHANGED
@@ -4,6 +4,6 @@ module XCRes
4
4
  #
5
5
  # XCRes’s version, following [semver](http://semver.org).
6
6
  #
7
- VERSION = "0.4.4"
7
+ VERSION = "0.5.0"
8
8
 
9
9
  end
@@ -16,3 +16,4 @@
16
16
 
17
17
  // Strings from Storyboards
18
18
  "123-abc-3e7.text" = "Hello Storyboards";
19
+ "123-ab-3e7.text" = "Hello Storyboards";
data/spec/integration.rb CHANGED
@@ -56,6 +56,10 @@ describe_cli 'xcres' do
56
56
  describe 'with resource which has a protected name' do
57
57
  behaves_like cli_spec('build-keyword-clash', '', 'build Example .')
58
58
  end
59
+
60
+ describe 'with swift' do
61
+ behaves_like cli_spec('build-swift', '', 'build --swift Example .')
62
+ end
59
63
  end
60
64
 
61
65
  describe 'Install' do
@@ -74,6 +78,10 @@ describe_cli 'xcres' do
74
78
  describe 'with moved supporting files' do
75
79
  behaves_like cli_spec('install-moved-supporting-files', '', 'install Example')
76
80
  end
81
+
82
+ describe 'with Swift' do
83
+ behaves_like cli_spec('install-swift', '', 'install --swift Example')
84
+ end
77
85
  end
78
86
 
79
87
  describe 'Get help' do
@@ -7,7 +7,5 @@
7
7
 
8
8
  #import <Foundation/Foundation.h>
9
9
 
10
- extern const struct R {
11
- struct Strings {
12
- } Strings;
10
+ FOUNDATION_EXTERN const struct R {
13
11
  } R;