xcoder 0.1.4 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -2
- data/README.md +63 -3
- data/lib/xcode/builder.rb +21 -8
- data/lib/xcode/configuration.rb +166 -19
- data/lib/xcode/configurations/array_property.rb +33 -0
- data/lib/xcode/configurations/boolean_property.rb +42 -0
- data/lib/xcode/configurations/space_delimited_string_property.rb +47 -0
- data/lib/xcode/configurations/string_property.rb +25 -0
- data/lib/xcode/configurations/targeted_device_family_property.rb +45 -0
- data/lib/xcode/file_reference.rb +25 -5
- data/lib/xcode/group.rb +28 -8
- data/lib/xcode/project.rb +53 -29
- data/lib/xcode/registry.rb +42 -34
- data/lib/xcode/resource.rb +87 -47
- data/lib/xcode/simple_identifier_generator.rb +49 -2
- data/lib/xcode/target.rb +11 -8
- data/lib/xcode/test/formatters/junit_formatter.rb +10 -5
- data/lib/xcode/test/formatters/stdout_formatter.rb +62 -0
- data/lib/xcode/test/ocunit_report_parser.rb +122 -25
- data/lib/xcode/test/suite_result.rb +12 -4
- data/lib/xcode/test/test_result.rb +15 -10
- data/lib/xcode/variant_group.rb +4 -0
- data/lib/xcode/version.rb +1 -1
- data/lib/xcoder.rb +50 -0
- data/spec/builder_spec.rb +2 -0
- data/spec/configuration_spec.rb +141 -0
- data/spec/test_report_spec.rb +81 -19
- metadata +18 -12
data/lib/xcode/file_reference.rb
CHANGED
@@ -1,15 +1,30 @@
|
|
1
1
|
module Xcode
|
2
2
|
|
3
3
|
#
|
4
|
-
# Within the project file the
|
5
|
-
#
|
6
|
-
#
|
4
|
+
# Within the project file the FileReference represents a large number of objects
|
5
|
+
# related to files like source files, resources, frameworks, and system libraries.
|
6
|
+
#
|
7
|
+
# A FileReference is used as input to add to the various Build Phases.
|
8
|
+
#
|
9
|
+
# @see BuildPhase
|
10
|
+
# @see BuildFile
|
7
11
|
#
|
8
12
|
module FileReference
|
9
13
|
|
10
14
|
# This is the group for which this file is contained within.
|
15
|
+
# @return [Group] the group that contains this file.
|
11
16
|
attr_accessor :supergroup
|
12
17
|
|
18
|
+
#
|
19
|
+
# Generate the properties for a file. A name and a path option need to
|
20
|
+
# be specified in the properties.
|
21
|
+
#
|
22
|
+
# @note a 'name' and 'path' key need to be specified in the framework for
|
23
|
+
# the framework to be added correctly.
|
24
|
+
#
|
25
|
+
# @param [Hash] properties to override or merge with the base properties.
|
26
|
+
# @return [Hash] properties of a file
|
27
|
+
#
|
13
28
|
def self.file(properties)
|
14
29
|
default_properties = { 'isa' => 'PBXFileReference',
|
15
30
|
'path' => nil,
|
@@ -49,7 +64,8 @@ module Xcode
|
|
49
64
|
# @param [String] name of the system framework which can be specified with or
|
50
65
|
# without the ".framework" suffix / extension.
|
51
66
|
# @param [Hash] properties the parameters to override for the system framework
|
52
|
-
#
|
67
|
+
# @return [Hash] system framework properties
|
68
|
+
#
|
53
69
|
def self.system_framework(name,properties = {})
|
54
70
|
|
55
71
|
name = name[/(.+)(?:\.framework)?$/,1]
|
@@ -73,7 +89,8 @@ module Xcode
|
|
73
89
|
# @param [String] name of the system library, which can be found by default
|
74
90
|
# in the /usr/lib folder.
|
75
91
|
# @param [Types] properties the parameters to override for the system library
|
76
|
-
#
|
92
|
+
# @return [Hash] system library properties
|
93
|
+
#
|
77
94
|
def self.system_library(name,properties = {})
|
78
95
|
default_properties = { 'isa' => 'PBXFileReference',
|
79
96
|
'lastKnownFileType' => 'compiled.mach-o.dylib',
|
@@ -94,6 +111,9 @@ module Xcode
|
|
94
111
|
# path = newtarget.app;
|
95
112
|
# sourceTree = BUILT_PRODUCTS_DIR; };
|
96
113
|
#
|
114
|
+
# @param [String] name name of the app product
|
115
|
+
# @return [Hash] app product properties
|
116
|
+
#
|
97
117
|
def self.app_product(name)
|
98
118
|
{ 'isa' => 'PBXFileReference',
|
99
119
|
'explicitFileType' => 'wrapper.application',
|
data/lib/xcode/group.rb
CHANGED
@@ -26,6 +26,7 @@ module Xcode
|
|
26
26
|
# Return the hash that maps to the properties for a logical group
|
27
27
|
#
|
28
28
|
# @param [String] name of the logical group
|
29
|
+
# @return [Hash] the properties for a Group
|
29
30
|
#
|
30
31
|
def self.logical_group(name)
|
31
32
|
{ 'isa' => 'PBXGroup',
|
@@ -68,7 +69,9 @@ module Xcode
|
|
68
69
|
|
69
70
|
#
|
70
71
|
# Find all the non-group objects within the group and return them
|
71
|
-
#
|
72
|
+
#
|
73
|
+
# @return [Array<Resource>] the children of the group, excluding the
|
74
|
+
# groups, which is usually composed of FileReferences
|
72
75
|
#
|
73
76
|
def files
|
74
77
|
children.reject {|child| child.is_a?(Group) }
|
@@ -86,11 +89,18 @@ module Xcode
|
|
86
89
|
end
|
87
90
|
|
88
91
|
#
|
89
|
-
# Check whether a file or group is contained within this group
|
90
|
-
#
|
92
|
+
# Check whether a file or group is contained within this group that has a name
|
93
|
+
# that matches the one specified
|
94
|
+
#
|
95
|
+
# @param [String] name of the group attempting to be found.
|
96
|
+
#
|
97
|
+
# @return [Array<Resource>] resource with the name that matches; empty array
|
98
|
+
# if no matches were found.
|
99
|
+
#
|
91
100
|
def exists?(name)
|
92
101
|
children.find_all {|child| child.name == name }
|
93
102
|
end
|
103
|
+
|
94
104
|
#
|
95
105
|
# Adds a group as a child to current group with the given name.
|
96
106
|
#
|
@@ -99,7 +109,9 @@ module Xcode
|
|
99
109
|
#
|
100
110
|
# @param [String] name of the group that you want to add as a child group of
|
101
111
|
# the specified group.
|
102
|
-
#
|
112
|
+
#
|
113
|
+
# @return [Group] the created group
|
114
|
+
#
|
103
115
|
def create_group(name)
|
104
116
|
new_group = create_child_object Group.logical_group(name)
|
105
117
|
new_group.supergroup = self
|
@@ -120,7 +132,9 @@ module Xcode
|
|
120
132
|
#
|
121
133
|
# @param [String,Hash] path to the file that is being added or a hash that
|
122
134
|
# contains the values would be merged with the default values.
|
123
|
-
#
|
135
|
+
#
|
136
|
+
# @return [FileReference] the file created.
|
137
|
+
#
|
124
138
|
def create_file(file_properties)
|
125
139
|
# This allows both support for the string value or the hash as the parameter
|
126
140
|
file_properties = { 'path' => file_properties } if file_properties.is_a? String
|
@@ -151,6 +165,8 @@ module Xcode
|
|
151
165
|
# @param [Hash] framework_properties the properties to merge with the default
|
152
166
|
# properties.
|
153
167
|
#
|
168
|
+
# @return [FileReference] the framework created.
|
169
|
+
#
|
154
170
|
def create_framework(framework_properties)
|
155
171
|
find_or_create_child_object FileReference.framework(framework_properties)
|
156
172
|
end
|
@@ -164,7 +180,8 @@ module Xcode
|
|
164
180
|
# project.frameworks_group.create_system_framework "Foundation"
|
165
181
|
#
|
166
182
|
# @param [String] name the name of the System framework to add to this group.
|
167
|
-
#
|
183
|
+
# @return [FileReference] the system framework created.
|
184
|
+
#
|
168
185
|
def create_system_framework(name)
|
169
186
|
find_or_create_child_object FileReference.system_framework(name)
|
170
187
|
end
|
@@ -177,7 +194,8 @@ module Xcode
|
|
177
194
|
# project.frameworks_group.create_system_library "libz.dylib"
|
178
195
|
#
|
179
196
|
# @param [String] name the name of the System Library to add to this group.
|
180
|
-
#
|
197
|
+
# @return [FileReference] the system library created.
|
198
|
+
#
|
181
199
|
def create_system_library(name)
|
182
200
|
find_or_create_child_object FileReference.system_library(name)
|
183
201
|
end
|
@@ -189,7 +207,8 @@ module Xcode
|
|
189
207
|
# properties.
|
190
208
|
#
|
191
209
|
# @see VariantGroup#info_plist
|
192
|
-
#
|
210
|
+
# @return [VariantGroup] the infoplist created
|
211
|
+
#
|
193
212
|
def create_infoplist(infoplist_properties)
|
194
213
|
create_child_object VariantGroup.info_plist(infoplist_properties)
|
195
214
|
end
|
@@ -203,6 +222,7 @@ module Xcode
|
|
203
222
|
# @see Target#create_product_reference
|
204
223
|
#
|
205
224
|
# @param [String] name the name of the product to generate
|
225
|
+
# @return [FileReference] the app product created.
|
206
226
|
#
|
207
227
|
def create_product_reference(name)
|
208
228
|
create_child_object FileReference.app_product(name)
|
data/lib/xcode/project.rb
CHANGED
@@ -1,20 +1,40 @@
|
|
1
|
-
require 'plist'
|
2
1
|
require 'xcode/parsers/plutil_project_parser'
|
3
2
|
require 'xcode/resource'
|
4
|
-
require 'xcode/target'
|
5
|
-
require 'xcode/configuration'
|
6
|
-
require 'xcode/scheme'
|
7
|
-
require 'xcode/group'
|
8
|
-
require 'xcode/file_reference'
|
9
3
|
require 'xcode/registry'
|
10
|
-
require 'xcode/build_phase'
|
11
|
-
require 'xcode/variant_group'
|
12
|
-
require 'xcode/configuration_list'
|
13
4
|
|
14
5
|
module Xcode
|
6
|
+
|
7
|
+
#
|
8
|
+
# The project is the representation of an Xcode Project folder, the `*.xcodeproj`,
|
9
|
+
# folder that contains a number of workspace files and project files like
|
10
|
+
# `project.pbxproj`.
|
11
|
+
#
|
12
|
+
# The Project represents the top-most element within the structure. It contains
|
13
|
+
# most of the methods that allow you to traverse through the targets and
|
14
|
+
# configurations that it is composed.
|
15
|
+
#
|
15
16
|
class Project
|
16
17
|
|
17
|
-
|
18
|
+
# @return [String] the name of the project; This value is deteremined from the
|
19
|
+
# first part of the Xcode project folder name (e.g. "TestProject.xcodeproj"
|
20
|
+
# name is "TestProject")
|
21
|
+
attr_reader :name
|
22
|
+
|
23
|
+
# @return [String] the sdks for the project. This is specified during the project
|
24
|
+
# initialization. If none are provided this currently defaults to "iphoneos"
|
25
|
+
attr_reader :sdk
|
26
|
+
|
27
|
+
# @return [String] the expanded file path for the project. This is expanded from the
|
28
|
+
# file path specified during initialization.
|
29
|
+
attr_reader :path
|
30
|
+
|
31
|
+
# @return [Array<Scheme>] the schemes that are found within the project path.
|
32
|
+
attr_reader :schemes
|
33
|
+
|
34
|
+
# @return [Registry] the data that is parsed from the project.pbxproj, it is
|
35
|
+
# in most part a Hash with additional methods included to provide core
|
36
|
+
# functionality.
|
37
|
+
attr_reader :registry
|
18
38
|
|
19
39
|
#
|
20
40
|
# Initialized with a specific path and sdk.
|
@@ -61,7 +81,7 @@ module Xcode
|
|
61
81
|
#
|
62
82
|
# Returns the main group of the project where all the files reside.
|
63
83
|
#
|
64
|
-
# @todo this really could use a better name then groups as it is the
|
84
|
+
# @todo this really could use a better name then groups as it is the main group
|
65
85
|
# but it should likely be something like main_group, root or something
|
66
86
|
# else that conveys that this is the project root for files, and such.
|
67
87
|
#
|
@@ -78,20 +98,22 @@ module Xcode
|
|
78
98
|
# the path the group is created. Also paths can be specified to make the
|
79
99
|
# traversing of the groups easier.
|
80
100
|
#
|
81
|
-
# @
|
101
|
+
# @note this will attempt to find the paths specified, if it fails to find them
|
102
|
+
# it will create one and then continue traversing.
|
103
|
+
#
|
104
|
+
# @example Traverse a path through the various sub-groups.
|
82
105
|
#
|
83
106
|
# project.group('Vendor/MyCode/Support Files')
|
84
|
-
# # is equivalent to...
|
107
|
+
# # is equivalent to ...
|
85
108
|
# project.group('Vendor').first.group('MyCode').first.group('Supporting Files')
|
86
109
|
#
|
87
110
|
# @note this path functionality current is only exercised from the project level
|
88
111
|
# all groups will treat the path division `/` as simply a character.
|
89
112
|
#
|
90
|
-
# @note this will attempt to find the paths specified, if it fails to find them
|
91
|
-
# it will create one and then continue traversing.
|
92
|
-
#
|
93
113
|
# @param [String] name the group name to find/create
|
94
114
|
#
|
115
|
+
# @return [Group] the group with the specified name.
|
116
|
+
#
|
95
117
|
def group(name,options = {},&block)
|
96
118
|
# By default create missing groups along the way
|
97
119
|
options = { :create => true }.merge(options)
|
@@ -222,7 +244,7 @@ module Xcode
|
|
222
244
|
#
|
223
245
|
# All the targets specified within the project.
|
224
246
|
#
|
225
|
-
# @return [Array<
|
247
|
+
# @return [Array<Target>] an array of all the available targets for
|
226
248
|
# the specific project.
|
227
249
|
#
|
228
250
|
def targets
|
@@ -239,7 +261,7 @@ module Xcode
|
|
239
261
|
# @note if two targets match names, the first matching target is returned.
|
240
262
|
#
|
241
263
|
# @param [String] name of the specific target
|
242
|
-
# @return [
|
264
|
+
# @return [Target] the specific target that matches the name specified
|
243
265
|
#
|
244
266
|
def target(name)
|
245
267
|
target = targets.select {|t| t.name == name.to_s}.first
|
@@ -264,6 +286,8 @@ module Xcode
|
|
264
286
|
# @param [String] name the name to provide to the target. This will also
|
265
287
|
# be the value that other defaults will be based on.
|
266
288
|
#
|
289
|
+
# @return [Target] the target created.
|
290
|
+
#
|
267
291
|
def create_target(name,type=:ios)
|
268
292
|
|
269
293
|
target = @registry.add_object Target.send(type)
|
@@ -294,16 +318,17 @@ module Xcode
|
|
294
318
|
# @param [String] name the name of the target to remove from the Xcode
|
295
319
|
# project.
|
296
320
|
#
|
321
|
+
# @return [Target] the target that has been removed.
|
322
|
+
#
|
297
323
|
def remove_target(name)
|
298
324
|
found_target = targets.find {|target| target.name == name }
|
299
325
|
if found_target
|
300
326
|
@project.properties['targets'].delete found_target.identifier
|
301
327
|
@registry.remove_object found_target.identifier
|
302
328
|
end
|
329
|
+
found_target
|
303
330
|
end
|
304
331
|
|
305
|
-
|
306
|
-
|
307
332
|
#
|
308
333
|
# Prints to STDOUT a description of this project's targets, configuration and schemes.
|
309
334
|
#
|
@@ -330,6 +355,9 @@ module Xcode
|
|
330
355
|
# the schemes will load the shared ones and then the current acting user's
|
331
356
|
# schemes.
|
332
357
|
#
|
358
|
+
# @return [Array<Scheme>] the shared schemes and user specific schemes found
|
359
|
+
# within the projet at the path defined for schemes.
|
360
|
+
#
|
333
361
|
def parse_schemes
|
334
362
|
shared_schemes = Dir["#{@path}/xcshareddata/xcschemes/*.xcscheme"]
|
335
363
|
user_specific_schemes = Dir["#{@path}/xcuserdata/#{ENV['USER']}.xcuserdatad/xcschemes/*.xcscheme"]
|
@@ -341,16 +369,12 @@ module Xcode
|
|
341
369
|
|
342
370
|
#
|
343
371
|
# Using the sytem tool plutil, the specified project file is parsed and
|
344
|
-
# converted to JSON, which is then converted to a hash object.
|
345
|
-
#
|
346
|
-
#
|
347
|
-
# to create the Registry.
|
348
|
-
#
|
349
|
-
# @return [Resource] a resource mapped to the root resource within the project
|
350
|
-
# this is generally the project file which contains details about the main
|
351
|
-
# group, targets, etc.
|
372
|
+
# converted to JSON, which is then converted to a hash object. This content
|
373
|
+
# contains all the data within the project file and is used to create the
|
374
|
+
# Registry.
|
352
375
|
#
|
353
|
-
# @
|
376
|
+
# @return [Registry] the representation of the project, this is a Hash with
|
377
|
+
# additional methods to provide easier functionality.
|
354
378
|
#
|
355
379
|
def parse_pbxproj
|
356
380
|
registry = Xcode::PLUTILProjectParser.parse "#{@path}/project.pbxproj"
|
data/lib/xcode/registry.rb
CHANGED
@@ -1,17 +1,33 @@
|
|
1
|
+
require 'xcode/build_file'
|
2
|
+
require 'xcode/build_phase'
|
3
|
+
require 'xcode/configuration'
|
4
|
+
require 'xcode/configuration_list'
|
5
|
+
require 'xcode/file_reference'
|
6
|
+
require 'xcode/group'
|
7
|
+
require 'xcode/resource'
|
8
|
+
require 'xcode/scheme'
|
1
9
|
require 'xcode/simple_identifier_generator'
|
10
|
+
require 'xcode/target'
|
11
|
+
require 'xcode/variant_group'
|
2
12
|
|
3
13
|
module Xcode
|
4
14
|
|
5
15
|
#
|
6
|
-
# The Registry represents the parsed data from the Xcode Project file.
|
7
|
-
#
|
16
|
+
# The Registry represents the parsed data from the Xcode Project file. The
|
17
|
+
# registry is a Hash that provides additional functionality to allow the
|
8
18
|
# the ability to query, add, and remove resources from the object hash.
|
9
19
|
#
|
10
20
|
# Opening the Xcode project file in a text-editor you'll notice that it is a
|
11
|
-
# big hash/plist
|
12
|
-
#
|
13
|
-
# objects
|
14
|
-
#
|
21
|
+
# big hash/plist. The registry represents this structure and provides access
|
22
|
+
# to the top-level items: 'rootObject'; 'objectVersion'; 'archiveVersion' and
|
23
|
+
# 'objects'. The registry provides a number of methods to access these items.
|
24
|
+
#
|
25
|
+
# The most important key is the 'objects' dictionary which maintains the
|
26
|
+
# master-list of Identifiers to properties. The registry provides additional
|
27
|
+
# methods get, add, remove, and update the objects stored within it. The
|
28
|
+
# registry returns {Resource} objects which is a wrapper class around the
|
29
|
+
# properties hash that would normally be returned. Providing additional
|
30
|
+
# functionality to make it easier to traverse the project.
|
15
31
|
#
|
16
32
|
# @see Project
|
17
33
|
#
|
@@ -21,18 +37,31 @@ module Xcode
|
|
21
37
|
# This method is used internally to determine if the value that is being
|
22
38
|
# retrieved is an identifier.
|
23
39
|
#
|
40
|
+
# @see Resource#define_property
|
41
|
+
#
|
24
42
|
# @param [String] value is the specified value in the form of an identifier
|
25
|
-
#
|
43
|
+
# @return [TrueClass,FalseClass] true if the value specified is a valid
|
44
|
+
# identifier; false if it is not.
|
45
|
+
#
|
26
46
|
def self.is_identifier? value
|
27
47
|
value =~ /^[0-9A-F]{24}$/
|
28
48
|
end
|
29
49
|
|
30
50
|
#
|
31
|
-
#
|
32
|
-
#
|
51
|
+
# All object parameters contain an `isa` property, which represents the class
|
52
|
+
# within Xcode. Here the `isa` string value is translated into a Ruby module.
|
53
|
+
#
|
54
|
+
# Initially the `isa` values were mapped directly to Ruby modules but that
|
55
|
+
# was changed to this model to make it easy to repair if Xcode were to
|
56
|
+
# change their `isa` values and also provide the ability to mixin different
|
57
|
+
# functionality as needed.
|
58
|
+
#
|
59
|
+
# @see Resource#initialize
|
33
60
|
#
|
34
61
|
# @param [String] isa the type of the object.
|
35
|
-
#
|
62
|
+
# @return [Module] the module name mapped to the parameter. If the parameter
|
63
|
+
# matches no module then a nil is returned.
|
64
|
+
#
|
36
65
|
def self.isa_to_module isa
|
37
66
|
|
38
67
|
{ 'XCBuildConfiguration' => Configuration,
|
@@ -53,6 +82,8 @@ module Xcode
|
|
53
82
|
# This is the root object of the project. This is generally an identifier
|
54
83
|
# pointing to a project.
|
55
84
|
#
|
85
|
+
# @return [Resource] this is traditionally the root, project object.
|
86
|
+
#
|
56
87
|
def root
|
57
88
|
self['rootObject']
|
58
89
|
end
|
@@ -108,8 +139,6 @@ module Xcode
|
|
108
139
|
objects[identifier]
|
109
140
|
end
|
110
141
|
|
111
|
-
MAX_IDENTIFIER_GENERATION_ATTEMPTS = 10
|
112
|
-
|
113
142
|
#
|
114
143
|
# Provides a method to generically add objects to the registry. This will
|
115
144
|
# create a unqiue identifier and add the specified parameters to the
|
@@ -124,28 +153,7 @@ module Xcode
|
|
124
153
|
# that are known for the particular item.
|
125
154
|
#
|
126
155
|
def add_object(object_properties)
|
127
|
-
|
128
|
-
new_identifier = SimpleIdentifierGenerator.generate
|
129
|
-
|
130
|
-
# Ensure that the identifier generated is unique
|
131
|
-
|
132
|
-
identifier_generation_count = 0
|
133
|
-
|
134
|
-
while objects.key?(new_identifier)
|
135
|
-
|
136
|
-
new_identifier = SimpleIdentifierGenerator.generate
|
137
|
-
|
138
|
-
# Increment our identifier generation count and if we reach our max raise
|
139
|
-
# an exception as something has gone horribly wrong.
|
140
|
-
|
141
|
-
identifier_generation_count += 1
|
142
|
-
if identifier_generation_count > MAX_IDENTIFIER_GENERATION_ATTEMPTS
|
143
|
-
raise "Unable to generate a unique identifier for object: #{object_properties}"
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
new_identifier = SimpleIdentifierGenerator.generate if objects.key?(new_identifier)
|
148
|
-
|
156
|
+
new_identifier = SimpleIdentifierGenerator.generate :existing_keys => objects.keys
|
149
157
|
|
150
158
|
objects[new_identifier] = object_properties
|
151
159
|
|
data/lib/xcode/resource.rb
CHANGED
@@ -1,82 +1,111 @@
|
|
1
1
|
require 'xcode/core_ext/string'
|
2
|
+
require 'xcode/registry'
|
2
3
|
|
3
4
|
module Xcode
|
4
5
|
|
5
6
|
#
|
6
7
|
# Resources are not represented as a true entity within an Xcode project.
|
7
|
-
#
|
8
|
-
# yourself interacting with these objects. As they represent a class that
|
9
|
-
# acts as a shim around
|
8
|
+
# However when traversing through groups, targets, configurations, etc. you will
|
9
|
+
# find yourself interacting with these objects. As they represent a class that
|
10
|
+
# acts as a shim around their hash data.
|
10
11
|
#
|
11
|
-
#
|
12
|
+
# The goal of the {Resource} is to aid in the navigation through the project
|
13
|
+
# and provide a flexible system to allow for Xcoder to adapt to changes to
|
14
|
+
# the Xcode project format.
|
12
15
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# easy access to those elements. This is
|
17
|
-
#
|
18
|
-
#
|
16
|
+
# A Resource requires an identifier and an instance of the {Registry}. Based
|
17
|
+
# on the supplied identifier, it peforms a look up of it's properties or hash
|
18
|
+
# of data. With that hash it then proceeds to create methods that allow for
|
19
|
+
# easy read/write access to those property elements. This is similar to Ruby's
|
20
|
+
# OpenStruct.
|
21
|
+
#
|
22
|
+
# @example Accessing the contents of a file reference
|
19
23
|
#
|
20
|
-
#
|
24
|
+
# file = project.file('IOSApp/IOSAppDelegate.m').properties # =>
|
21
25
|
#
|
22
26
|
# { 'isa' => 'PBXFileReference',
|
23
27
|
# 'lastKnownFileType' => 'sourcecode.c.h',
|
24
28
|
# 'path' => IOSAppDelegate.h',
|
25
29
|
# 'sourceTree' => "<group>" }
|
26
30
|
#
|
27
|
-
#
|
28
|
-
#
|
31
|
+
# file.isa # => 'PBXFileReference'
|
32
|
+
# file.last_known_file_type # => 'sourcecode.c.h'
|
33
|
+
# file.path # => 'IOSAppDelegate.m'
|
34
|
+
# file.path = "NewIOSAppDelegate.m" # => 'NewIOSAppDeleget.m'
|
35
|
+
# file.source_tree # => "<group>"
|
29
36
|
#
|
37
|
+
# In the above example, you can still gain access to the internal properties
|
38
|
+
# through the {#properties} method. However, the {Resource} provides for you
|
39
|
+
# additional ruby friendly methods to access the properties.
|
30
40
|
#
|
31
41
|
# To provide additional convenience when traversing through the
|
32
|
-
# various objects, the
|
42
|
+
# various objects, the getter methods will check to see if the value
|
33
43
|
# being returned matches that of a unique identifier. If it does, instead of
|
34
|
-
# providing that identifier
|
35
|
-
#
|
44
|
+
# providing that identifier, it will instead look in the {Registry} for the
|
45
|
+
# object that matches and return a new Resource automatically.
|
46
|
+
#
|
47
|
+
# @example Magically accessing resources through resources
|
36
48
|
#
|
37
|
-
#
|
49
|
+
# group = project.groups
|
50
|
+
# group.properties # =>
|
38
51
|
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
52
|
+
# { "children"=>["7165D45A146B4EA100DE2F0E",
|
53
|
+
# "7165D472146B4EA100DE2F0E",
|
54
|
+
# "7165D453146B4EA100DE2F0E",
|
55
|
+
# "7165D451146B4EA100DE2F0E"],
|
56
|
+
# "isa"=>"PBXGroup",
|
57
|
+
# "sourceTree"=>"<group>"}
|
45
58
|
#
|
46
|
-
# group
|
47
|
-
# subgroup = group.group('Models')
|
59
|
+
# group.children.first # =>
|
48
60
|
#
|
61
|
+
# PBXGroup 7165D45A146B4EA100DE2F0E {"children"=>["7165D463146B4EA100DE2F0E",
|
62
|
+
# "7165D464146B4EA100DE2F0E",
|
63
|
+
# "7165D45B146B4EA100DE2F0E"],
|
64
|
+
# "isa"=>"PBXGroup",
|
65
|
+
# "path"=>"TestProject",
|
66
|
+
# "sourceTree"=>"<group>"}
|
49
67
|
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
# functionality with it automatically.
|
68
|
+
# In this example when accessing the first element of children instead of an
|
69
|
+
# identifier string being returned the child resource is returned. This
|
70
|
+
# functionality is in place to allow Xcoder to flexibly conform to new relationships
|
71
|
+
# that may exist or come to exist.
|
55
72
|
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
73
|
+
# Lastly, a {Resource} is simply not enough to describe most of the objects
|
74
|
+
# within an Xcode project as each object has unique functionality that needs
|
75
|
+
# to be able to perform. So each resource when it is created will query the
|
76
|
+
# {Registry#isa_to_module} hash to determine the functionality that it needs
|
77
|
+
# to additionally extend into the Resource.
|
78
|
+
#
|
79
|
+
# This `isa` property mapped to Ruby modules allows for the easy expansion of
|
80
|
+
# new objects or for changes to be made to existing ones as needed.
|
60
81
|
#
|
61
82
|
class Resource
|
62
83
|
|
63
|
-
#
|
84
|
+
# @return [String] the unique identifier for this resource
|
64
85
|
attr_accessor :identifier
|
65
86
|
|
66
|
-
# The properties hash that is known about the resource
|
87
|
+
# The raw properties hash that is known about the resource. This is the best
|
88
|
+
# way to manipulate the raw values of the resource.
|
89
|
+
#
|
90
|
+
# @return [Hash] the raw properties hash for the object
|
67
91
|
attr_accessor :properties
|
68
92
|
|
69
93
|
# The registry of all objects within the project file which all resources
|
70
94
|
# have a reference to so that they can retrieve any items they may own that
|
71
|
-
# are simply referenced by identifiers.
|
72
|
-
|
95
|
+
# are simply referenced by identifiers. This registry is used to convert
|
96
|
+
# identifier keys to resource objects. It is also passed to any resources
|
97
|
+
# that are created.
|
98
|
+
#
|
99
|
+
# @return [Registry] the registry for the entire project.
|
100
|
+
attr_reader :registry
|
73
101
|
|
74
102
|
#
|
75
103
|
# Definiing a property allows the creation of an alias to the actual value.
|
76
104
|
# This level of indirection allows for the replacement of values which are
|
77
105
|
# identifiers with a resource representation of it.
|
78
106
|
#
|
79
|
-
# @note This is used internally by the resource when it is created
|
107
|
+
# @note This is used internally by the resource when it is created to create
|
108
|
+
# the getter/setter methods.
|
80
109
|
#
|
81
110
|
# @param [String] name of the property
|
82
111
|
# @param [String] value of the property
|
@@ -128,6 +157,8 @@ module Xcode
|
|
128
157
|
|
129
158
|
end
|
130
159
|
|
160
|
+
# Generate a setter method for this property based on the given name.
|
161
|
+
|
131
162
|
self.class.send :define_method, "#{name.underscore}=" do |new_value|
|
132
163
|
@properties[name] = new_value
|
133
164
|
end
|
@@ -136,22 +167,25 @@ module Xcode
|
|
136
167
|
end
|
137
168
|
|
138
169
|
#
|
139
|
-
#
|
140
|
-
#
|
141
|
-
#
|
170
|
+
# A Resource is created during {Project#initialize}, when the project is
|
171
|
+
# first parsed. Afterwards each Resource is usually generated through the
|
172
|
+
# special getter method defined through {#define_property}.
|
173
|
+
#
|
174
|
+
# @see Project#initialize
|
175
|
+
# @see #defined_property
|
142
176
|
#
|
143
177
|
# @param [String] identifier the unique identifier for this resource.
|
144
|
-
# @param [
|
178
|
+
# @param [Registry] registry the core registry for the system.
|
145
179
|
#
|
146
|
-
def initialize identifier,
|
147
|
-
@registry =
|
180
|
+
def initialize identifier, registry
|
181
|
+
@registry = registry
|
148
182
|
@properties = {}
|
149
183
|
@identifier = identifier
|
150
184
|
|
151
185
|
# Create property methods for all of the key-value pairs found in the
|
152
186
|
# registry for specified identifier.
|
153
187
|
|
154
|
-
Array(
|
188
|
+
Array(registry.properties(@identifier)).each do |key,value|
|
155
189
|
send :define_property, key, value
|
156
190
|
end
|
157
191
|
|
@@ -171,6 +205,13 @@ module Xcode
|
|
171
205
|
# Saves the current resource back to the registry. This is necessary as
|
172
206
|
# any changes made are not automatically saved back into the registry.
|
173
207
|
#
|
208
|
+
# @example group adding a files and then saving itself
|
209
|
+
#
|
210
|
+
# group = project.groups
|
211
|
+
# group.create_file 'name' => 'AppDelegate.m', 'path' => 'AppDelegate.m'
|
212
|
+
# group.save!
|
213
|
+
#
|
214
|
+
# @return [Resource] the object that is being saved.
|
174
215
|
def save!
|
175
216
|
@registry.set_object(self)
|
176
217
|
self
|
@@ -194,7 +235,6 @@ module Xcode
|
|
194
235
|
def to_xcplist
|
195
236
|
%{
|
196
237
|
#{@identifier} = { #{ @properties.map {|k,v| "#{k} = \"#{v.to_xcplist}\"" }.join("; ") } }
|
197
|
-
|
198
238
|
}
|
199
239
|
end
|
200
240
|
|