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.
Files changed (32) hide show
  1. data/bin/xcodeproj +13 -0
  2. data/lib/xcodeproj.rb +13 -1
  3. data/lib/xcodeproj/command.rb +131 -0
  4. data/lib/xcodeproj/command/project_diff.rb +53 -0
  5. data/lib/xcodeproj/command/show.rb +35 -0
  6. data/lib/xcodeproj/command/target_diff.rb +43 -0
  7. data/lib/xcodeproj/config.rb +66 -38
  8. data/lib/xcodeproj/constants.rb +146 -0
  9. data/lib/xcodeproj/helper.rb +28 -0
  10. data/lib/xcodeproj/project.rb +462 -156
  11. data/lib/xcodeproj/project/object.rb +251 -138
  12. data/lib/xcodeproj/project/object/build_configuration.rb +27 -0
  13. data/lib/xcodeproj/project/object/build_file.rb +26 -0
  14. data/lib/xcodeproj/project/object/build_phase.rb +132 -61
  15. data/lib/xcodeproj/project/object/build_rule.rb +46 -0
  16. data/lib/xcodeproj/project/object/configuration_list.rb +47 -0
  17. data/lib/xcodeproj/project/object/container_item_proxy.rb +49 -0
  18. data/lib/xcodeproj/project/object/file_reference.rb +80 -48
  19. data/lib/xcodeproj/project/object/group.rb +213 -89
  20. data/lib/xcodeproj/project/object/native_target.rb +171 -114
  21. data/lib/xcodeproj/project/object/root_object.rb +66 -0
  22. data/lib/xcodeproj/project/object/target_dependency.rb +23 -0
  23. data/lib/xcodeproj/project/object_attributes.rb +382 -0
  24. data/lib/xcodeproj/project/object_list.rb +64 -118
  25. data/lib/xcodeproj/project/recursive_diff.rb +116 -0
  26. data/lib/xcodeproj/workspace.rb +56 -2
  27. metadata +38 -10
  28. data/lib/xcodeproj/project/association.rb +0 -54
  29. data/lib/xcodeproj/project/association/has_many.rb +0 -51
  30. data/lib/xcodeproj/project/association/has_one.rb +0 -39
  31. data/lib/xcodeproj/project/association/reflection.rb +0 -86
  32. 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