xcoder 0.1.4 → 0.1.6
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.
- 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
|
|