xcodeproj 0.3.5 → 0.4.0.rc1
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/bin/xcodeproj +13 -0
- data/lib/xcodeproj.rb +13 -1
- data/lib/xcodeproj/command.rb +131 -0
- data/lib/xcodeproj/command/project_diff.rb +53 -0
- data/lib/xcodeproj/command/show.rb +35 -0
- data/lib/xcodeproj/command/target_diff.rb +43 -0
- data/lib/xcodeproj/config.rb +66 -38
- data/lib/xcodeproj/constants.rb +146 -0
- data/lib/xcodeproj/helper.rb +28 -0
- data/lib/xcodeproj/project.rb +462 -156
- data/lib/xcodeproj/project/object.rb +251 -138
- data/lib/xcodeproj/project/object/build_configuration.rb +27 -0
- data/lib/xcodeproj/project/object/build_file.rb +26 -0
- data/lib/xcodeproj/project/object/build_phase.rb +132 -61
- data/lib/xcodeproj/project/object/build_rule.rb +46 -0
- data/lib/xcodeproj/project/object/configuration_list.rb +47 -0
- data/lib/xcodeproj/project/object/container_item_proxy.rb +49 -0
- data/lib/xcodeproj/project/object/file_reference.rb +80 -48
- data/lib/xcodeproj/project/object/group.rb +213 -89
- data/lib/xcodeproj/project/object/native_target.rb +171 -114
- data/lib/xcodeproj/project/object/root_object.rb +66 -0
- data/lib/xcodeproj/project/object/target_dependency.rb +23 -0
- data/lib/xcodeproj/project/object_attributes.rb +382 -0
- data/lib/xcodeproj/project/object_list.rb +64 -118
- data/lib/xcodeproj/project/recursive_diff.rb +116 -0
- data/lib/xcodeproj/workspace.rb +56 -2
- metadata +38 -10
- data/lib/xcodeproj/project/association.rb +0 -54
- data/lib/xcodeproj/project/association/has_many.rb +0 -51
- data/lib/xcodeproj/project/association/has_one.rb +0 -39
- data/lib/xcodeproj/project/association/reflection.rb +0 -86
- data/lib/xcodeproj/project/object/configuration.rb +0 -97
@@ -0,0 +1,66 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
class Project
|
3
|
+
module Object
|
4
|
+
|
5
|
+
# This class represents the root object of a project document.
|
6
|
+
#
|
7
|
+
class PBXProject < AbstractObject
|
8
|
+
|
9
|
+
# @return [ObjectList<PBXNativeTarget>] a list of all the targets in
|
10
|
+
# the project.
|
11
|
+
#
|
12
|
+
has_many :targets, PBXNativeTarget
|
13
|
+
|
14
|
+
# @return [Hash{String => String}] attributes the attributes of the
|
15
|
+
# target.
|
16
|
+
#
|
17
|
+
# The hash might contain the following keys:
|
18
|
+
#
|
19
|
+
# - `CLASSPREFIX`
|
20
|
+
# - `LastUpgradeCheck`
|
21
|
+
# - `ORGANIZATIONNAME`
|
22
|
+
#
|
23
|
+
attribute :attributes, Hash, {'LastUpgradeCheck' => '0450'}
|
24
|
+
|
25
|
+
# @return [XCConfigurationList] the configuration list of the project.
|
26
|
+
#
|
27
|
+
has_one :build_configuration_list, XCConfigurationList
|
28
|
+
|
29
|
+
# @return [String] the compatibility version of the project.
|
30
|
+
#
|
31
|
+
attribute :compatibility_version, String, 'Xcode 3.2'
|
32
|
+
|
33
|
+
# @return [String] the development region of the project.
|
34
|
+
#
|
35
|
+
attribute :development_region, String, 'English'
|
36
|
+
|
37
|
+
# @return [String] whether the project has scanned for encodings.
|
38
|
+
#
|
39
|
+
attribute :has_scanned_for_encodings, String, '0'
|
40
|
+
|
41
|
+
# @return [Array<String>] the list of known regions.
|
42
|
+
#
|
43
|
+
attribute :known_regions, Array, ['en']
|
44
|
+
|
45
|
+
# @return [PBXGroup] the main group of the project. The one displayed
|
46
|
+
# by Xcode in the Project Navigator.
|
47
|
+
#
|
48
|
+
has_one :main_group, PBXGroup
|
49
|
+
|
50
|
+
# @return [PBXGroup] the group containing the references to products of
|
51
|
+
# the project.
|
52
|
+
#
|
53
|
+
has_one :product_ref_group, PBXGroup
|
54
|
+
|
55
|
+
# @return [String] the directory of the project.
|
56
|
+
#
|
57
|
+
attribute :project_dir_path, String
|
58
|
+
|
59
|
+
# @return [String] the root of the project.
|
60
|
+
#
|
61
|
+
attribute :project_root, String
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
class Project
|
3
|
+
module Object
|
4
|
+
|
5
|
+
# Represents a dependency of a target on another one.
|
6
|
+
#
|
7
|
+
class PBXTargetDependency < AbstractObject
|
8
|
+
|
9
|
+
# @return [PBXNativeTarget] the target that needs to be built to
|
10
|
+
# satisfy the dependency.
|
11
|
+
#
|
12
|
+
has_one :target, PBXNativeTarget
|
13
|
+
|
14
|
+
# @return [PBXContainerItemProxy] a proxy for the target that needs to
|
15
|
+
# be built. Apparently to support targets in other projects of the
|
16
|
+
# same workspace.
|
17
|
+
#
|
18
|
+
has_one :targetProxy, PBXContainerItemProxy
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,382 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
class Project
|
3
|
+
module Object
|
4
|
+
|
5
|
+
# This class represents an attribute of {AbstractObject} subclasses.
|
6
|
+
# Attributes are created by the {AbstractObject} DSL methods and allow to
|
7
|
+
# mirror the underlying attributes of the xcodeproj document model.
|
8
|
+
#
|
9
|
+
# Attributes provide support for runtime type checking. They also allow
|
10
|
+
# {AbstractObject} initialization and serialization to plist.
|
11
|
+
#
|
12
|
+
# @todo Add support for a list of required values so objects can be
|
13
|
+
# validated before serialization ?
|
14
|
+
#
|
15
|
+
class AbstractObjectAttribute
|
16
|
+
|
17
|
+
require 'active_support/inflector'
|
18
|
+
|
19
|
+
# @return [Symbol] the type of the attribute. It can be `:simple`,
|
20
|
+
# `:to_one`, `:to_many`.
|
21
|
+
#
|
22
|
+
attr_reader :type
|
23
|
+
|
24
|
+
# @return [Symbol] the name of the attribute.
|
25
|
+
#
|
26
|
+
attr_reader :name
|
27
|
+
|
28
|
+
# @return [Class] the class that owns the attribute.
|
29
|
+
#
|
30
|
+
attr_accessor :owner
|
31
|
+
|
32
|
+
# Creates a new attribute with the given type and name.
|
33
|
+
#
|
34
|
+
# Attributes are expected to be instantiated only by the
|
35
|
+
# {AbstractObject} DSL methods.
|
36
|
+
#
|
37
|
+
# @param [Symbol] type
|
38
|
+
# the type of the attribute.
|
39
|
+
#
|
40
|
+
# @param [Symbol] name
|
41
|
+
# the name of the attribute.
|
42
|
+
#
|
43
|
+
# @param [Class] owner
|
44
|
+
# the class that owns the attribute.
|
45
|
+
#
|
46
|
+
def initialize(type, name, owner)
|
47
|
+
@type = type
|
48
|
+
@name = name
|
49
|
+
@owner = owner
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return[String] The name of the attribute in camel case.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# attribute.new(:simple, project_root)
|
56
|
+
# attribute.plist_name #=> projectRoot
|
57
|
+
#
|
58
|
+
def plist_name
|
59
|
+
case name
|
60
|
+
when :remote_global_id_string
|
61
|
+
# `_id_` would become `Id`
|
62
|
+
'remoteGlobalIDString'
|
63
|
+
else
|
64
|
+
name.to_s.camelize(:lower)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Array<Class>] the list of the classes accepted by the
|
69
|
+
# attribute.
|
70
|
+
#
|
71
|
+
attr_accessor :classes
|
72
|
+
|
73
|
+
# @return [String, Array, Hash] the default value, if any, for simple
|
74
|
+
# attributes.
|
75
|
+
#
|
76
|
+
attr_accessor :default_value
|
77
|
+
|
78
|
+
# Convenience method that returns the value of this attribute for a
|
79
|
+
# given object.
|
80
|
+
#
|
81
|
+
# @param [AbstractObject] object
|
82
|
+
# the object for which the value of this attribute is requested.
|
83
|
+
#
|
84
|
+
# @return [String, Array, Hash, AbstractObject, ObjectList]
|
85
|
+
# the value.
|
86
|
+
#
|
87
|
+
def get_value(object)
|
88
|
+
object.send("#{name}")
|
89
|
+
end
|
90
|
+
|
91
|
+
# Convenience method that sets the value of this attribute for a
|
92
|
+
# given object. It makes sense only for `:simple` or `:to_one`
|
93
|
+
# attributes.
|
94
|
+
#
|
95
|
+
# @raise It the type of this attribute is `:to_many`.
|
96
|
+
#
|
97
|
+
# @param [AbstractObject] object
|
98
|
+
# the object for which to set the value.
|
99
|
+
#
|
100
|
+
# @param [String, Hash, Array, AbstractObject] new_value
|
101
|
+
# the value to set for the attribute.
|
102
|
+
#
|
103
|
+
# @return [void]
|
104
|
+
#
|
105
|
+
def set_value(object, new_value)
|
106
|
+
raise "[Xcodeproj] Set value called for to many attribute" if type == :to_many
|
107
|
+
object.send("#{name}=", new_value)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Convenience method that sets the value of this attribute for a
|
111
|
+
# given object to the default (if any). It makes sense only for
|
112
|
+
# `:simple` attributes.
|
113
|
+
#
|
114
|
+
# @param [AbstractObject] object
|
115
|
+
# the object for which to set the default value.
|
116
|
+
#
|
117
|
+
# @return [void]
|
118
|
+
#
|
119
|
+
def set_default(object)
|
120
|
+
raise "[Xcodeproj] Set value called for to many attribute" unless type == :simple
|
121
|
+
set_value(object, default_value) if default_value
|
122
|
+
end
|
123
|
+
|
124
|
+
# Checks that a given value is compatible with the attribute.
|
125
|
+
#
|
126
|
+
# This method powers the runtime type checking of the {AbstractObject}
|
127
|
+
# and is used its by synthesised methods.
|
128
|
+
#
|
129
|
+
# @raise If the class of the value is not compatible with the attribute.
|
130
|
+
#
|
131
|
+
# @return [void]
|
132
|
+
#
|
133
|
+
def validate_value(object)
|
134
|
+
return unless object
|
135
|
+
acceptable = classes.find { |klass| object.class == klass || object.class < klass }
|
136
|
+
if type == :simple
|
137
|
+
raise "[Xcodeproj] Type checking error: '#{owner.isa}' expected '#{classes.inspect}' got '#{object.class}' for attribute: #{inspect}" unless acceptable
|
138
|
+
else
|
139
|
+
raise "[Xcodeproj] Type checking error: '#{owner.isa}' expected #{classes.map(&:isa)} got #{object.isa} for attribute: #{inspect}" unless acceptable
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def inspect
|
144
|
+
"#<name: '#{name}', type: '#{type}', classes: '#{classes}', owner class: '#{owner.isa}'>"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class AbstractObject
|
149
|
+
|
150
|
+
# The {AbstractObject} DSL methods allow to specify with fidelity the
|
151
|
+
# underlying model of the xcodeproj document format. {AbstractObject}
|
152
|
+
# subclasses should specify their attributes through the following
|
153
|
+
# methods:
|
154
|
+
#
|
155
|
+
# - `{AbstractObject.attribute}`
|
156
|
+
# - `{AbstractObject.has_one}`
|
157
|
+
# - `{AbstractObject.has_many}`
|
158
|
+
#
|
159
|
+
# The subclasses should not interfere with the methods synthesised by
|
160
|
+
# the DSL and should only implement convenience methods in top of them.
|
161
|
+
#
|
162
|
+
# Attributes are typed and are validated at runtime.
|
163
|
+
#
|
164
|
+
class << self
|
165
|
+
|
166
|
+
# @return [Array<AbstractObjectAttribute>] the attributes associated
|
167
|
+
# with the class.
|
168
|
+
#
|
169
|
+
# @note It includes the attributes defined in the superclass and the
|
170
|
+
# list is cleaned for duplicates. Subclasses should not duplicate
|
171
|
+
# an attribute of the superclass but for the method implementation
|
172
|
+
# they will duplicate them.
|
173
|
+
#
|
174
|
+
def attributes
|
175
|
+
unless @full_attributes
|
176
|
+
attributes = @attributes || []
|
177
|
+
super_attributes = superclass.respond_to?(:attributes) ? superclass.attributes : []
|
178
|
+
# The uniqueness of the attributes is very important because the
|
179
|
+
# initialization from plist deletes the values from the dictionary.
|
180
|
+
@full_attributes = attributes.concat(super_attributes).uniq
|
181
|
+
end
|
182
|
+
@full_attributes
|
183
|
+
end
|
184
|
+
|
185
|
+
# @return [Array<AbstractObjectAttribute>] the simple attributes
|
186
|
+
# associated with with the class.
|
187
|
+
#
|
188
|
+
def simple_attributes
|
189
|
+
@simple_attributes ||= attributes.select { |a| a.type == :simple }
|
190
|
+
end
|
191
|
+
|
192
|
+
# @return [Array<AbstractObjectAttribute>] the attributes
|
193
|
+
# representing a to one relationship associated with with the
|
194
|
+
# class.
|
195
|
+
#
|
196
|
+
def to_one_attributes
|
197
|
+
@to_one_attributes ||= attributes.select { |a| a.type == :to_one }
|
198
|
+
end
|
199
|
+
|
200
|
+
# @return [Array<AbstractObjectAttribute>] the attributes
|
201
|
+
# representing a to many relationship associated with with the
|
202
|
+
# class.
|
203
|
+
#
|
204
|
+
def to_many_attributes
|
205
|
+
@to_many_attributes ||= attributes.select { |a| a.type == :to_many }
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
|
210
|
+
# Defines a new simple attribute and synthesises the corresponding
|
211
|
+
# methods.
|
212
|
+
#
|
213
|
+
# @note Simple attributes are directly stored in a hash. They can
|
214
|
+
# contain only a string, array of strings or a hash containing
|
215
|
+
# strings and thus they are not affected by reference counting.
|
216
|
+
# Clients can access the hash directly through the
|
217
|
+
# {AbstractObject#simple_attributes_hash} method.
|
218
|
+
#
|
219
|
+
# @param [Symbol] name
|
220
|
+
# the name of the attribute.
|
221
|
+
#
|
222
|
+
# @param [Class] klass
|
223
|
+
# the accepted {Class} for the values of the attribute.
|
224
|
+
#
|
225
|
+
# @param [String, Array<String>, Hash{String=>String}] default_value
|
226
|
+
# the default value for new objects.
|
227
|
+
#
|
228
|
+
# @example
|
229
|
+
# attribute project_root
|
230
|
+
# #=> leads to the creation of the following methods
|
231
|
+
#
|
232
|
+
# def project_root
|
233
|
+
# @simple_attributes_hash[projectRoot]
|
234
|
+
# end
|
235
|
+
#
|
236
|
+
# def project_root=(value)
|
237
|
+
# attribute.validate_value(value)
|
238
|
+
# @simple_attributes_hash[projectRoot] = value
|
239
|
+
# end
|
240
|
+
#
|
241
|
+
# @macro [attach] attribute
|
242
|
+
# @!attribute [rw] $1
|
243
|
+
#
|
244
|
+
def attribute(name, klass, default_value = nil)
|
245
|
+
attrb = AbstractObjectAttribute.new(:simple, name, self)
|
246
|
+
attrb.classes = [klass]
|
247
|
+
attrb.default_value = default_value
|
248
|
+
add_attribute(attrb)
|
249
|
+
|
250
|
+
define_method(attrb.name) do
|
251
|
+
@simple_attributes_hash ||= {}
|
252
|
+
@simple_attributes_hash[attrb.plist_name]
|
253
|
+
end
|
254
|
+
|
255
|
+
define_method("#{attrb.name}=") do |value|
|
256
|
+
@simple_attributes_hash ||= {}
|
257
|
+
attrb.validate_value(value)
|
258
|
+
@simple_attributes_hash[attrb.plist_name] = value
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Defines a new relationship to a single and synthesises the
|
263
|
+
# corresponding methods.
|
264
|
+
#
|
265
|
+
# @note The synthesised setter takes care of handling reference
|
266
|
+
# counting directly.
|
267
|
+
#
|
268
|
+
# @param [String] singular_name
|
269
|
+
# the name of the relationship.
|
270
|
+
#
|
271
|
+
# @param [Class, Array<Class>] isas
|
272
|
+
# the list of the classes corresponding to the accepted isas for
|
273
|
+
# this relationship.
|
274
|
+
#
|
275
|
+
# @macro [attach] has_one
|
276
|
+
# @!attribute [rw] $1
|
277
|
+
#
|
278
|
+
def has_one(singular_name, isas)
|
279
|
+
isas = [isas] unless isas.is_a?(Array)
|
280
|
+
attrb = AbstractObjectAttribute.new(:to_one, singular_name, self)
|
281
|
+
attrb.classes = isas
|
282
|
+
add_attribute(attrb)
|
283
|
+
|
284
|
+
attr_reader(attrb.name)
|
285
|
+
|
286
|
+
define_method("#{attrb.name}=") do |value|
|
287
|
+
attrb.validate_value(value)
|
288
|
+
|
289
|
+
previous_value = send(attrb.name)
|
290
|
+
previous_value.remove_referrer(self) if previous_value
|
291
|
+
instance_variable_set("@#{attrb.name}", value)
|
292
|
+
value.add_referrer(self) if value
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# Defines a new ordered relationship to many.
|
297
|
+
#
|
298
|
+
# @note This attribute only generates the reader method. Clients are
|
299
|
+
# not supposed to create {ObjectList} objects which are created
|
300
|
+
# by the methods synthesised by this attribute on demand.
|
301
|
+
# Clients, however can mutate the list according to its
|
302
|
+
# interface. The list is responsible to manage the reference
|
303
|
+
# counting for its values.
|
304
|
+
#
|
305
|
+
# @param [String] plural_name
|
306
|
+
# the name of the relationship.
|
307
|
+
#
|
308
|
+
# @param [Class, Array<Class>] isas
|
309
|
+
# the list of the classes corresponding to the accepted isas for
|
310
|
+
# this relationship.
|
311
|
+
#
|
312
|
+
# @macro [attach] has_many
|
313
|
+
# @!attribute [r] $1
|
314
|
+
#
|
315
|
+
def has_many(plural_name, isas)
|
316
|
+
isas = [isas] unless isas.is_a?(Array)
|
317
|
+
|
318
|
+
attrb = AbstractObjectAttribute.new(:to_many, plural_name, self)
|
319
|
+
attrb.classes = isas
|
320
|
+
add_attribute(attrb)
|
321
|
+
|
322
|
+
define_method(attrb.name) do
|
323
|
+
# Here we are in the context of the instance
|
324
|
+
list = instance_variable_get("@#{attrb.name}")
|
325
|
+
unless list
|
326
|
+
list = ObjectList.new(attrb, self)
|
327
|
+
instance_variable_set("@#{attrb.name}", list)
|
328
|
+
end
|
329
|
+
list
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
protected
|
334
|
+
|
335
|
+
# Adds an attribute to the list of attributes of the class.
|
336
|
+
#
|
337
|
+
# @note This method is intended to be invoked only by the
|
338
|
+
# {AbstractObject} meta programming methods
|
339
|
+
#
|
340
|
+
# @return [void]
|
341
|
+
#
|
342
|
+
def add_attribute(attribute)
|
343
|
+
raise "[Xcodeproj] BUG - missing classes for #{attribute.inspect}" unless attribute.classes
|
344
|
+
raise "[Xcodeproj] BUG - classes:#{attribute.classes} for #{attribute.inspect}" unless attribute.classes.all? { |klass| klass.is_a?(Class) }
|
345
|
+
@attributes ||= []
|
346
|
+
@attributes << attribute
|
347
|
+
end
|
348
|
+
end # AbstractObject << self
|
349
|
+
|
350
|
+
# @return [Hash] the simple attributes hash.
|
351
|
+
#
|
352
|
+
attr_reader :simple_attributes_hash
|
353
|
+
|
354
|
+
# @!group xcodeproj format attributes
|
355
|
+
|
356
|
+
# @return (see AbstractObject.attributes)
|
357
|
+
#
|
358
|
+
def attributes
|
359
|
+
self.class.attributes
|
360
|
+
end
|
361
|
+
|
362
|
+
# @return (see AbstractObject.simple_attributes)
|
363
|
+
#
|
364
|
+
def simple_attributes
|
365
|
+
self.class.simple_attributes
|
366
|
+
end
|
367
|
+
|
368
|
+
# @return (see AbstractObject.to_one_attributes)
|
369
|
+
#
|
370
|
+
def to_one_attributes
|
371
|
+
self.class.to_one_attributes
|
372
|
+
end
|
373
|
+
|
374
|
+
# @return (see AbstractObject.to_many_attributes)
|
375
|
+
#
|
376
|
+
def to_many_attributes
|
377
|
+
self.class.to_many_attributes
|
378
|
+
end
|
379
|
+
end # AbstractObject
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|