xcodeproj 0.4.0.rc2 → 0.4.0.rc3

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/lib/xcodeproj.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Xcodeproj
2
- VERSION = '0.4.0.rc2'
2
+ VERSION = '0.4.0.rc3'
3
3
 
4
4
  class PlainInformative < StandardError
5
5
  end
@@ -16,31 +16,37 @@ module Xcodeproj
16
16
  #
17
17
  KNOWN_ISAS = {
18
18
  'AbstractObject' => %w[
19
- PBXBuildFile
20
- AbstractBuildPhase
21
- PBXBuildRule
22
- XCBuildConfiguration
23
- XCConfigurationList
24
- PBXContainerItemProxy
25
- PBXFileReference
26
- PBXGroup
27
- PBXNativeTarget
28
- PBXProject
29
- PBXTargetDependency
19
+ PBXBuildFile
20
+ AbstractBuildPhase
21
+ PBXBuildRule
22
+ XCBuildConfiguration
23
+ XCConfigurationList
24
+ PBXContainerItemProxy
25
+ PBXFileReference
26
+ PBXGroup
27
+ PBXProject
28
+ PBXTargetDependency
29
+ PBXReferenceProxy
30
30
  ],
31
31
 
32
32
  'AbstractBuildPhase' => %w[
33
- PBXCopyFilesBuildPhase
34
- PBXResourcesBuildPhase
35
- PBXSourcesBuildPhase
36
- PBXFrameworksBuildPhase
37
- PBXHeadersBuildPhase
38
- PBXShellScriptBuildPhase
33
+ PBXCopyFilesBuildPhase
34
+ PBXResourcesBuildPhase
35
+ PBXSourcesBuildPhase
36
+ PBXFrameworksBuildPhase
37
+ PBXHeadersBuildPhase
38
+ PBXShellScriptBuildPhase
39
+ ],
40
+
41
+ 'AbstractTarget' => %w[
42
+ PBXNativeTarget
43
+ PBXAggregateTarget
44
+ PBXLegacyTarget
39
45
  ],
40
46
 
41
47
  'PBXGroup' => %w[
42
- XCVersionGroup
43
- PBXVariantGroup
48
+ XCVersionGroup
49
+ PBXVariantGroup
44
50
  ]
45
51
  }.freeze
46
52
 
@@ -176,6 +176,7 @@ module Xcodeproj
176
176
  #
177
177
  def new_from_plist(uuid, objects_by_uuid_plist, root_object = false)
178
178
  attributes = objects_by_uuid_plist[uuid]
179
+ raise "[Xcodeproj] Unable to find attributes for UUID #{uuid}" unless attributes
179
180
  klass = Object.const_get(attributes['isa'])
180
181
  object = klass.new(self, uuid)
181
182
  object.add_referrer(self) if root_object
@@ -156,6 +156,11 @@ module Xcodeproj
156
156
  list = attrb.get_value(self)
157
157
  list.delete(object)
158
158
  end
159
+
160
+ references_by_keys_attributes.each do |attrb|
161
+ list = attrb.get_value(self)
162
+ list.each { |dictionary| dictionary.remove_reference(object) }
163
+ end
159
164
  end
160
165
 
161
166
  # @!group Plist related methods
@@ -191,12 +196,25 @@ module Xcodeproj
191
196
  to_many_attributes.each do |attrb|
192
197
  ref_uuids = object_plist[attrb.plist_name] || []
193
198
  list = attrb.get_value(self)
194
- ref_uuids.each do |ref_uuid|
195
- ref = project.objects_by_uuid[ref_uuid] || project.new_from_plist(ref_uuid, objects_by_uuid_plist)
196
- list << ref
199
+ ref_uuids.each do |uuid|
200
+ list << object_with_uuid(uuid, objects_by_uuid_plist)
201
+ end
202
+ object_plist.delete(attrb.plist_name)
203
+ end
204
+
205
+ references_by_keys_attributes.each do |attrb|
206
+ hashes = object_plist[attrb.plist_name] || {}
207
+ list = attrb.get_value(self)
208
+ hashes.each do |hash|
209
+ dictionary = ObjectDictionary.new(attrb, self)
210
+ hash.each do |key, uuid|
211
+ dictionary[key] = object_with_uuid(uuid, objects_by_uuid_plist)
212
+ end
213
+ list << dictionary
197
214
  end
198
215
  object_plist.delete(attrb.plist_name)
199
216
  end
217
+
200
218
  unless object_plist.empty?
201
219
  raise "[!] Xcodeproj doesn't know about the following attributes " \
202
220
  "#{object_plist} for the '#{isa}' isa.\n" \
@@ -204,6 +222,15 @@ module Xcodeproj
204
222
  end
205
223
  end
206
224
 
225
+ def object_with_uuid(uuid, objects_by_uuid_plist)
226
+ project.objects_by_uuid[uuid] || project.new_from_plist(uuid, objects_by_uuid_plist)
227
+ rescue NameError => exception
228
+ attributes = objects_by_uuid_plist[uuid]
229
+ raise "`#{isa}` attempted to initialize an object with unknown ISA "\
230
+ "`#{attributes['isa']}` from attributes: `#{attributes}`\n" \
231
+ "Please file and issue: https://github.com/CocoaPods/Xcodeproj/issues/new"
232
+ end
233
+
207
234
  # @note the key for simple and to_one attributes usually appears only
208
235
  # if there is a value. To many keys always appear with an empty
209
236
  # array.
@@ -227,6 +254,11 @@ module Xcodeproj
227
254
  plist[attrb.plist_name] = list.uuids
228
255
  end
229
256
 
257
+ references_by_keys_attributes.each do |attrb|
258
+ list = attrb.get_value(self)
259
+ plist[attrb.plist_name] = list.map { |dictionary| dictionary.to_plist }
260
+ end
261
+
230
262
  plist
231
263
  end
232
264
  alias :to_hash :to_plist
@@ -262,6 +294,11 @@ module Xcodeproj
262
294
  hash[attrb.plist_name] = list.map { |obj| obj.to_tree_hash }
263
295
  end
264
296
 
297
+ references_by_keys_attributes.each do |attrb|
298
+ list = attrb.get_value(self)
299
+ hash[attrb.plist_name] = list.map { |dictionary| dictionary.to_tree_hash }
300
+ end
301
+
265
302
  hash
266
303
  end
267
304
 
@@ -285,8 +322,9 @@ module Xcodeproj
285
322
  end
286
323
  end
287
324
 
288
- require 'xcodeproj/project/object_attributes'
289
325
  require 'xcodeproj/project/object_list'
326
+ require 'xcodeproj/project/object_dictionary'
327
+ require 'xcodeproj/project/object_attributes'
290
328
 
291
329
  # Required because some classes have cyclical references to each other.
292
330
  #
@@ -317,4 +355,5 @@ require 'xcodeproj/project/object/group'
317
355
  require 'xcodeproj/project/object/native_target'
318
356
  require 'xcodeproj/project/object/root_object'
319
357
  require 'xcodeproj/project/object/target_dependency'
358
+ require 'xcodeproj/project/object/reference_proxy'
320
359
 
File without changes
@@ -121,6 +121,12 @@ module Xcodeproj
121
121
 
122
122
  end
123
123
 
124
+ # Apparently a build phase named `Build Carbon Resources` (Observed for
125
+ # kernel extensions targets).
126
+ #
127
+ class PBXRezBuildPhase < AbstractBuildPhase
128
+ end
129
+
124
130
  class AbstractBuildPhase < AbstractObject
125
131
 
126
132
  ## CONVENIENCE METHODS #################################################
@@ -148,13 +154,42 @@ module Xcodeproj
148
154
  files << build_file
149
155
  build_file
150
156
  end
151
-
157
+
158
+ # Removes the build file associated with the given file reference from
159
+ # the phase.
160
+ #
161
+ # @param [PBXFileReference] file the file to remove
162
+ #
163
+ # @return [void]
164
+ #
152
165
  def remove_file_reference(file)
153
166
  build_file = files.find { |bf| bf.file_ref == file }
154
- files.delete(build_file)
155
167
  build_file.file_ref = nil
156
168
  build_file.remove_from_project
157
169
  end
170
+
171
+ # Removes a build file from the phase and clears its relationship to
172
+ # the file reference.
173
+ #
174
+ # @param [PBXBuildFile] file the file to remove
175
+ #
176
+ # @return [void]
177
+ #
178
+ def remove_build_file(build_file)
179
+ build_file.file_ref = nil
180
+ build_file.remove_from_project
181
+ end
182
+
183
+ # Removes all the build files from the phase and clears their
184
+ # relationship to the file reference.
185
+ #
186
+ # @return [void]
187
+ #
188
+ def clear_build_files
189
+ files.objects.each do |bf|
190
+ remove_build_file(bf)
191
+ end
192
+ end
158
193
  end
159
194
  end
160
195
  end
@@ -8,21 +8,32 @@ module Xcodeproj
8
8
  # This class is referenced by {PBXTargetDependency}; for information
9
9
  # about it usage see the specs of that class.
10
10
  #
11
- # @note This class references the other objects by uuid instead of
11
+ # @note This class references the other objects by UUID instead of
12
12
  # creating proper relationships because the other objects might be
13
13
  # part of another project. This implies that the references to
14
- # other objects should not increase the retain coutn of the
14
+ # other objects should not increase the retain count of the
15
15
  # targets.
16
16
  #
17
- # @todo: this class needs some work to support targets accross workspaces,
17
+ # @todo: this class needs some work to support targets across workspaces,
18
18
  # as the container portal might not be initialized leading
19
- # xcodproj to raise because ti can't find the UUID.
19
+ # xcodeproj to raise because ti can't find the UUID.
20
20
  #
21
21
  class PBXContainerItemProxy < AbstractObject
22
22
 
23
23
  # @return [String] apparently the UUID of the root object
24
24
  # {PBXProject} of the project containing the represented object.
25
25
  #
26
+ # @todo this is an attribute because a it is usually a reference to the
27
+ # root object or to a file reference to another project. The
28
+ # reference to the root object causes a retain cycle that could
29
+ # cause issues (e.g. in to_tree_hash). Usually those objects are
30
+ # retained by at least another object (the {Project} for the root
31
+ # object and a {PBXGroup} for the reference to another project)
32
+ # and so the referenced object should be serialized.
33
+ #
34
+ # If this assumption is incorrect, there could be loss of
35
+ # information opening and saving an existing project.
36
+ #
26
37
  attribute :container_portal, String
27
38
 
28
39
  # @return [String] the type of the proxy.
@@ -34,7 +45,15 @@ module Xcodeproj
34
45
  # @return [String] apparently the UUID of the represented
35
46
  # object.
36
47
  #
37
- # @note If the object is in another project this will return nil.
48
+ # @note If the object is in another project the UUID would not be
49
+ # present in the {Project#objects_by_uuid} hash. For this reason
50
+ # this is not an `has_one` attribute. It is assumes that if the
51
+ # object belongs to the project at least another object should be
52
+ # retaining it. This assumption is reasonable because this is a
53
+ # proxy class.
54
+ #
55
+ # If this assumption is incorrect, there could be loss of
56
+ # information opening and saving an existing project.
38
57
  #
39
58
  attribute :remote_global_id_string, String
40
59
 
@@ -10,7 +10,7 @@ module Xcodeproj
10
10
  # @return [ObjectList<PBXGroup, PBXFileReference>]
11
11
  # the objects contained by the group.
12
12
  #
13
- has_many :children, [PBXGroup, PBXFileReference]
13
+ has_many :children, [PBXGroup, PBXFileReference, PBXReferenceProxy]
14
14
 
15
15
  # @return [String] the source tree to which this group is relative.
16
16
  #
@@ -57,7 +57,7 @@ module Xcodeproj
57
57
 
58
58
  end
59
59
 
60
- # The purpose of this subclass is not understood.
60
+ # This class is used to gather localized files into one entry.
61
61
  #
62
62
  class PBXVariantGroup < PBXGroup
63
63
 
@@ -209,6 +209,16 @@ module Xcodeproj
209
209
  find_subpath(path)
210
210
  end
211
211
 
212
+ # Removes children files and groups under this group.
213
+ #
214
+ def remove_children_recursively
215
+ groups.each do |g|
216
+ g.remove_children_recursively
217
+ g.remove_from_project
218
+ end
219
+ files.each { |f| f.remove_from_project }
220
+ end
221
+
212
222
  # Traverses the children groups and finds the children with the given
213
223
  # path, optionally, creating any needed group. If the given path is
214
224
  # `nil` it returns itself.
@@ -2,20 +2,48 @@ module Xcodeproj
2
2
  class Project
3
3
  module Object
4
4
 
5
- # Represents a target.
6
- #
7
- class PBXNativeTarget < AbstractObject
5
+ class AbstractTarget < AbstractObject
8
6
 
9
7
  # @return [String] The name of the Target.
10
8
  #
11
9
  attribute :name, String
12
10
 
11
+ # @return [String] the name of the build product.
12
+ #
13
+ attribute :product_name, String
14
+
13
15
  # @return [XCConfigurationList] the list of the build configurations of
14
16
  # the target. This list commonly include two configurations `Debug`
15
17
  # and `Release`.
16
18
  #
17
19
  has_one :build_configuration_list, XCConfigurationList
18
20
 
21
+ # @return [PBXNativeTarget] the targets necessary to build this target.
22
+ #
23
+ has_many :dependencies, PBXTargetDependency
24
+
25
+ end
26
+
27
+ # Represents a target handled by Xcode.
28
+ #
29
+ class PBXNativeTarget < AbstractTarget
30
+
31
+ # @return [PBXBuildRule] the build rules of this target.
32
+ #
33
+ has_many :build_rules, PBXBuildRule
34
+
35
+ # @return [String] the build product type identifier.
36
+ #
37
+ attribute :product_type, String, 'com.apple.product-type.library.static'
38
+
39
+ # @return [PBXFileReference] the reference to the product file.
40
+ #
41
+ has_one :product_reference, PBXFileReference
42
+
43
+ # @return [String] the install path of the product.
44
+ #
45
+ attribute :product_install_path, String
46
+
19
47
  # @return [PBXBuildRule] the build phases of the target.
20
48
  #
21
49
  # @note Apparently only PBXCopyFilesBuildPhase and
@@ -23,31 +51,58 @@ module Xcodeproj
23
51
  #
24
52
  has_many :build_phases, AbstractBuildPhase
25
53
 
26
- # @return [PBXBuildRule] the build rules of this target.
54
+ end
55
+
56
+ # Represents a target that only consists in a aggregate of targets.
57
+ #
58
+ # @todo apparently it can't have build rules.
59
+ #
60
+ class PBXAggregateTarget < AbstractTarget
61
+
62
+ # @return [PBXBuildRule] the build phases of the target.
27
63
  #
28
- has_many :build_rules, PBXBuildRule
64
+ # @note Apparently only PBXCopyFilesBuildPhase and
65
+ # PBXShellScriptBuildPhase can appear multiple times in a target.
66
+ #
67
+ has_many :build_phases, [ PBXCopyFilesBuildPhase, PBXShellScriptBuildPhase ]
29
68
 
30
- # @return [PBXNativeTarget] the targets necessary to build this target.
69
+ end
70
+
71
+ # Represents a legacy target which uses an external build tool.
72
+ #
73
+ # Apparently it can't have any build phase but the attribute can be
74
+ # present.
75
+ #
76
+ class PBXLegacyTarget < AbstractTarget
77
+
78
+ # @return [String] e.g "Dir"
31
79
  #
32
- has_many :dependencies, PBXTargetDependency
80
+ attribute :build_working_directory, String
33
81
 
34
- # @return [String] the name of the build product.
82
+ # @return [String] e.g "$(ACTION)"
35
83
  #
36
- attribute :product_name, String
84
+ attribute :build_arguments_string, String
37
85
 
38
- # @return [String] the build product type identifier.
86
+ # @return [String] e.g "1"
39
87
  #
40
- attribute :product_type, String, 'com.apple.product-type.library.static'
88
+ attribute :pass_build_settings_in_environment, String
41
89
 
42
- # @return [PBXFileReference] the reference to the product file.
90
+ # @return [String] e.g "/usr/bin/make"
43
91
  #
44
- has_one :product_reference, PBXFileReference
92
+ attribute :build_tool_path, String
45
93
 
46
- # @return [String] the install path of the product.
94
+ # @return [PBXBuildRule] the build phases of the target.
47
95
  #
48
- attribute :product_install_path, String
96
+ # @note Apparently only PBXCopyFilesBuildPhase and
97
+ # PBXShellScriptBuildPhase can appear multiple times in a target.
98
+ #
99
+ has_many :build_phases, AbstractBuildPhase
100
+
101
+ end
102
+
103
+ #----------------------------------------------------------------------#
49
104
 
50
- ## CONVENIENCE METHODS #################################################
105
+ class AbstractTarget < AbstractObject
51
106
 
52
107
  # @!group Convenience methods
53
108
 
@@ -68,6 +123,54 @@ module Xcodeproj
68
123
  build_configuration_list.build_settings(build_configuration_name)
69
124
  end
70
125
 
126
+
127
+ # @return [Array<PBXCopyFilesBuildPhase>]
128
+ # the copy files build phases of the target.
129
+ #
130
+ def copy_files_build_phases
131
+ build_phases.select { |bp| bp.class == PBXCopyFilesBuildPhase }
132
+ end
133
+
134
+ # @return [Array<PBXShellScriptBuildPhase>]
135
+ # the copy files build phases of the target.
136
+ #
137
+ def shell_script_build_phases
138
+ build_phases.select { |bp| bp.class == PBXShellScriptBuildPhase }
139
+ end
140
+
141
+ # Creates a new copy files build phase.
142
+ #
143
+ # @param [String] name
144
+ # an optional name for the phase.
145
+ #
146
+ # @return [PBXCopyFilesBuildPhase] the new phase.
147
+ #
148
+ def new_copy_files_build_phase(name = nil)
149
+ phase = project.new(PBXCopyFilesBuildPhase)
150
+ phase.name = name
151
+ build_phases << phase
152
+ phase
153
+ end
154
+
155
+ # Creates a new shell script build phase.
156
+ #
157
+ # @param (see #new_copy_files_build_phase)
158
+ #
159
+ # @return [PBXShellScriptBuildPhase] the new phase.
160
+ #
161
+ def new_shell_script_build_phase(name = nil)
162
+ phase = project.new(PBXShellScriptBuildPhase)
163
+ phase.name = name
164
+ build_phases << phase
165
+ phase
166
+ end
167
+
168
+ end
169
+
170
+ class PBXNativeTarget < AbstractTarget
171
+
172
+ # @!group Convenience methods
173
+
71
174
  # Adds source files to the target.
72
175
  #
73
176
  # @param [Array<PBXFileReference>] file_references
@@ -88,8 +191,7 @@ module Xcodeproj
88
191
  header_extensions = Constants::HEADER_FILES_EXTENSIONS
89
192
  if (header_extensions.include?(extension))
90
193
  build_file.settings = { 'ATTRIBUTES' => ["Public"] }
91
- phase = headers_build_phase
92
- phase.files << build_file
194
+ headers_build_phase.files << build_file
93
195
  else
94
196
  build_file.settings = { 'COMPILER_FLAGS' => compiler_flags } if compiler_flags && !compiler_flags.empty?
95
197
  source_build_phase.files << build_file
@@ -97,9 +199,6 @@ module Xcodeproj
97
199
  end
98
200
  end
99
201
 
100
-
101
- # @!group Accessing build phases
102
-
103
202
  # Finds or creates the headers build phase of the target.
104
203
  #
105
204
  # @note A target should have only one headers build phase.
@@ -169,50 +268,6 @@ module Xcodeproj
169
268
  end
170
269
  bp
171
270
  end
172
-
173
- # @return [Array<PBXCopyFilesBuildPhase>]
174
- # the copy files build phases of the target.
175
- #
176
- def copy_files_build_phases
177
- build_phases.select { |bp| bp.class == PBXCopyFilesBuildPhase }
178
- end
179
-
180
- # @return [Array<PBXShellScriptBuildPhase>]
181
- # the copy files build phases of the target.
182
- #
183
- def shell_script_build_phases
184
- build_phases.select { |bp| bp.class == PBXShellScriptBuildPhase }
185
- end
186
-
187
-
188
- # @!group Creating build phases
189
-
190
- # Creates a new copy files build phase.
191
- #
192
- # @param [String] name
193
- # an optional name for the pahse.
194
- #
195
- # @return [PBXCopyFilesBuildPhase] the new phase.
196
- #
197
- def new_copy_files_build_phase(name = nil)
198
- phase = project.new(PBXCopyFilesBuildPhase)
199
- phase.name = name
200
- build_phases << phase
201
- phase
202
- end
203
-
204
- # Creates a new shell script build phase.
205
- #
206
- # @param (see #new_copy_files_build_phase)
207
- #
208
- # @return [PBXShellScriptBuildPhase] the new phase.
209
- #
210
- def new_shell_script_build_phase(name = nil)
211
- phase = project.new(PBXShellScriptBuildPhase)
212
- phase.name = name
213
- build_phases << phase
214
- phase
215
- end
216
271
  end
217
272
  end
218
273
  end
@@ -0,0 +1,35 @@
1
+ module Xcodeproj
2
+ class Project
3
+ module Object
4
+
5
+ # Apparently a proxy for a reference object which might belong another
6
+ # project contained in the same workspace of the project document.
7
+ #
8
+ # This class is used for referencing the products of another project.
9
+ #
10
+ class PBXReferenceProxy < AbstractObject
11
+
12
+ # @return [String] the path of the referenced filed.
13
+ #
14
+ attribute :path, String
15
+
16
+ # @return [String] the file type of the referenced filed.
17
+ #
18
+ attribute :file_type, String
19
+
20
+ # @return [PBXContainerItemProxy] the proxy to the project that
21
+ # contains the object.
22
+ #
23
+ has_one :remote_ref, PBXContainerItemProxy
24
+
25
+ # @return [String] the source tree for the path of the reference.
26
+ #
27
+ # E.g. "BUILT_PRODUCTS_DIR"
28
+ #
29
+ attribute :source_tree, String
30
+
31
+ end
32
+ end
33
+ end
34
+ end
35
+
@@ -9,7 +9,7 @@ module Xcodeproj
9
9
  # @return [ObjectList<PBXNativeTarget>] a list of all the targets in
10
10
  # the project.
11
11
  #
12
- has_many :targets, PBXNativeTarget
12
+ has_many :targets, AbstractTarget
13
13
 
14
14
  # @return [Hash{String => String}] attributes the attributes of the
15
15
  # target.
@@ -60,6 +60,13 @@ module Xcodeproj
60
60
  #
61
61
  attribute :project_root, String
62
62
 
63
+ # @return [Array<ObjectDictionary>] any reference to other projects.
64
+ #
65
+ has_many_references_by_keys :project_references, {
66
+ :project_ref => PBXFileReference,
67
+ :product_group => PBXGroup
68
+ }
69
+
63
70
  end
64
71
  end
65
72
  end
@@ -205,6 +205,10 @@ module Xcodeproj
205
205
  @to_many_attributes ||= attributes.select { |a| a.type == :to_many }
206
206
  end
207
207
 
208
+ def references_by_keys_attributes
209
+ @references_by_keys_attributes ||= attributes.select { |a| a.type == :references_by_keys }
210
+ end
211
+
208
212
  private
209
213
 
210
214
  # Defines a new simple attribute and synthesises the corresponding
@@ -330,6 +334,41 @@ module Xcodeproj
330
334
  end
331
335
  end
332
336
 
337
+ # Defines a new ordered relationship to many.
338
+ #
339
+ # @note This attribute only generates the reader method. Clients are
340
+ # not supposed to create {ObjectList} objects which are created
341
+ # by the methods synthesised by this attribute on demand.
342
+ # Clients, however can mutate the list according to its
343
+ # interface. The list is responsible to manage the reference
344
+ # counting for its values.
345
+ #
346
+ # @param [String] plural_name
347
+ # the name of the relationship.
348
+ #
349
+ # @param [Class, Array<Class>] isas
350
+ # the list of the classes corresponding to the accepted isas for
351
+ # this relationship.
352
+ #
353
+ # @macro [attach] has_many
354
+ # @!attribute [r] $1
355
+ #
356
+ def has_many_references_by_keys(plural_name, isas_hash)
357
+ attrb = AbstractObjectAttribute.new(:references_by_keys, plural_name, self)
358
+ attrb.classes = isas_hash.values
359
+ add_attribute(attrb)
360
+
361
+ define_method(attrb.name) do
362
+ # Here we are in the context of the instance
363
+ list = instance_variable_get("@#{attrb.name}")
364
+ unless list
365
+ list = ObjectList.new(attrb, self)
366
+ instance_variable_set("@#{attrb.name}", list)
367
+ end
368
+ list
369
+ end
370
+ end
371
+
333
372
  protected
334
373
 
335
374
  # Adds an attribute to the list of attributes of the class.
@@ -376,6 +415,12 @@ module Xcodeproj
376
415
  def to_many_attributes
377
416
  self.class.to_many_attributes
378
417
  end
418
+
419
+ # @return (see AbstractObject.to_many_attributes)
420
+ #
421
+ def references_by_keys_attributes
422
+ self.class.references_by_keys_attributes
423
+ end
379
424
  end # AbstractObject
380
425
  end
381
426
  end
@@ -0,0 +1,191 @@
1
+ module Xcodeproj
2
+ class Project
3
+
4
+ # This class represents relationships to other objects stored in a
5
+ # Dictionary.
6
+ #
7
+ # It works in conjunction with the {AbstractObject} class to ensure that
8
+ # the project is not serialized with unreachable objects by updating the
9
+ # with reference count on modifications.
10
+ #
11
+ # @note This class is a stub currently only being used by
12
+ # {PBXProject#project_references}. It doesn't perform type cheeking
13
+ # and the keys of the dictionary are in camel-case. To provide full
14
+ # support as the other classes the dictionary should be able to
15
+ #
16
+ # Give the following attribute:
17
+ #
18
+ # has_many_references_by_keys :project_references, {
19
+ # :project_ref => PBXFileReference,
20
+ # :product_group => PBXGroup
21
+ # }
22
+ #
23
+ # This should be possible:
24
+ #
25
+ # #=> Note the API:
26
+ # root_object.project_references.project_ref = file
27
+ #
28
+ # #=> This should raise:
29
+ # root_object.project_references.product_group = file
30
+ #
31
+ # generate setters and getters from the specification hash.
32
+ #
33
+ # Also the interface is a dirty hybrid between the
34
+ # {AbstractObjectAttribute} and the {ObjectList}.
35
+ #
36
+ # @note Concerning the mutations methods it is safe to call only those
37
+ # which are overridden to inform objects reference count. Ideally all
38
+ # the hash methods should be covered, but this is not done yet.
39
+ # Moreover it is a moving target because the methods of array
40
+ # usually are implemented in C
41
+ #
42
+ # @todo Cover all the mutations methods of the {Hash} class.
43
+ #
44
+ class ObjectDictionary < Hash
45
+
46
+ # {Xcodeproj} clients are not expected to create instances of
47
+ # {ObjectDictionary}, it is always initialized empty and automatically by
48
+ # the synthesized methods generated by {AbstractObject.has_many}.
49
+ #
50
+ def initialize(attribute, owner)
51
+ @attribute = attribute
52
+ @owner = owner
53
+ end
54
+
55
+ # @return [Array<Class>] The attribute that generated the list.
56
+ #
57
+ attr_reader :attribute
58
+
59
+ # @return [Array<Class>] The object that owns the list.
60
+ #
61
+ attr_reader :owner
62
+
63
+ #------------------------------------------------------------------------#
64
+
65
+ # @!group Notification enabled methods
66
+
67
+ # TODO: the overridden methods are incomplete.
68
+
69
+ # Associates an object to the given key and updates its references count.
70
+ #
71
+ # @param [String] key
72
+ # the key
73
+ #
74
+ # @param [AbstractObject] object
75
+ # the object to add to the dictionary.
76
+ #
77
+ # @return [void]
78
+ #
79
+ def []=(key, object)
80
+ if object
81
+ perform_additions_operations(object)
82
+ else
83
+ perform_deletion_operations(self[key])
84
+ end
85
+ super
86
+ end
87
+
88
+ # Removes the given key from the dictionary and informs the object that
89
+ # is not longer referenced by the owner.
90
+ #
91
+ # @param [String] key
92
+ # the key
93
+ #
94
+ # @return [void]
95
+ #
96
+ def delete(key)
97
+ object = self[key]
98
+ perform_deletion_operations(object)
99
+ super
100
+ end
101
+
102
+ #------------------------------------------------------------------------#
103
+
104
+ # @!group Integration with {AbstractObject}
105
+
106
+ # The plist reppresentation of the dictionary where the objects are
107
+ # replaced by their UUIDs.
108
+ #
109
+ # @return [Hash<String => String>]
110
+ #
111
+ def to_plist
112
+ result = {}
113
+ each { |key, obj| result[key] = obj.uuid }
114
+ result
115
+ end
116
+
117
+ # Returns a cascade reppresentation of the object without UUIDs.
118
+ #
119
+ # @return [Hash<String => String>]
120
+ #
121
+ def to_tree_hash
122
+ result = {}
123
+ each { |key, obj| result[key] = obj.to_tree_hash }
124
+ result
125
+ end
126
+
127
+ # Removes all the references to a given object.
128
+ #
129
+ # @return [void]
130
+ #
131
+ def remove_reference(object)
132
+ each { |key, obj| self[key] = nil if obj == object }
133
+ end
134
+
135
+ #------------------------------------------------------------------------#
136
+
137
+ # @!group Integration with {ObjectList}
138
+
139
+ # Informs the objects contained in the dictionary that another object is
140
+ # referencing them.
141
+ #
142
+ # @return [void]
143
+ #
144
+ def add_referrer(referrer)
145
+ values.each { |obj| obj.add_referrer(referrer) }
146
+ end
147
+
148
+ # Informs the objects contained in the dictionary that another object
149
+ # stopped referencing them.
150
+ #
151
+ # @return [void]
152
+ #
153
+ def remove_referrer(referrer)
154
+ values.each { |obj| obj.remove_referrer(referrer) }
155
+ end
156
+
157
+ #------------------------------------------------------------------------#
158
+
159
+ # @!group Notification Methods
160
+
161
+ private
162
+
163
+ # Informs an object that it was added to the dictionary. In practice it
164
+ # adds the owner of the list as referrer to the objects. It also
165
+ # validates the value.
166
+ #
167
+ # @return [void]
168
+ #
169
+ def perform_additions_operations(objects)
170
+ objects = [objects] unless objects.is_a?(Array)
171
+ objects.each do |obj|
172
+ obj.add_referrer(owner)
173
+ attribute.validate_value(obj)
174
+ end
175
+ end
176
+
177
+ # Informs an object that it was removed from to the dictionary, so it can
178
+ # remove it from its referrers and take the appropriate actions.
179
+ #
180
+ # @return [void]
181
+ #
182
+ def perform_deletion_operations(objects)
183
+ objects = [objects] unless objects.is_a?(Array)
184
+ objects.each do |obj|
185
+ obj.remove_referrer(owner)
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
191
+
@@ -10,10 +10,10 @@ module Xcodeproj
10
10
  # @note Concerning the mutations methods it is safe to call only those
11
11
  # which are overridden to inform objects reference count. Ideally all
12
12
  # the array methods should be covered, but this is not done yet.
13
- # Moreover it is a moving target because the methods of array
13
+ # Moreover it is a moving target because the methods of array
14
14
  # usually are implemented in C
15
15
  #
16
- # @todo Cover all the array methods.
16
+ # @todo Cover all the mutations methods of the {Array} class.
17
17
  #
18
18
  class ObjectList < Array
19
19
 
@@ -26,40 +26,90 @@ module Xcodeproj
26
26
  @owner = owner
27
27
  end
28
28
 
29
- # @return [Array<Class>] The attribute that generated the list.
29
+ # @return [Array<Class>] the attribute that generated the list.
30
30
  #
31
31
  attr_reader :attribute
32
32
 
33
- # @return [Array<Class>] The object that owns the list.
33
+ # @return [Array<Class>] the object that owns the list.
34
34
  #
35
35
  attr_reader :owner
36
36
 
37
- # @return [Array<String>] The UUIDs of all the objects referenced by this
38
- # list.
37
+ #------------------------------------------------------------------------#
38
+
39
+ # @!group Integration with {ObjectList}
40
+
41
+ # @return [Array<String>]
42
+ # the UUIDs of all the objects referenced by this list.
39
43
  #
40
44
  def uuids
41
45
  map { |obj| obj.uuid }
42
46
  end
43
47
 
48
+ # @return [Array<AbstractObject>]
49
+ # a new array generated with the objects contained in the list.
50
+ #
51
+ def objects
52
+ to_a
53
+ end
54
+
55
+ #------------------------------------------------------------------------#
56
+
44
57
  # @!group Notification enabled methods
45
58
 
46
59
  # TODO: the overridden methods are incomplete.
47
60
 
61
+ # Adds an array of objects to list and updates their references count.
62
+ #
63
+ # @param [Array<AbstractObject, ObjectDictionary>] object
64
+ # an array of objects to add to the list.
65
+ #
66
+ # @return [void]
67
+ #
48
68
  def +(objects)
49
69
  super
50
70
  perform_additions_operations(objects)
51
71
  end
52
72
 
73
+ # Adds an object to list and updates its references count.
74
+ #
75
+ # @param [AbstractObject, ObjectDictionary] object
76
+ # the object to add to the list.
77
+ #
78
+ # @return [void]
79
+ #
53
80
  def <<(object)
54
81
  super
55
82
  perform_additions_operations(object)
56
83
  end
57
84
 
85
+ # Removes an object to list and updates its references count.
86
+ #
87
+ # @param [AbstractObject, ObjectDictionary] object
88
+ # the object to delete from the list.
89
+ #
90
+ # @return [void]
91
+ #
58
92
  def delete(object)
59
93
  super
60
94
  perform_deletion_operations(object)
61
95
  end
62
96
 
97
+ # Removes all the objects contained in the list and updates their
98
+ # reference counts.
99
+ #
100
+ # @return [void]
101
+ #
102
+ def clear
103
+ objects.each do |object|
104
+ perform_deletion_operations(object)
105
+ end
106
+ super
107
+ end
108
+
109
+ #------------------------------------------------------------------------#
110
+
111
+ # @!group Notification Methods
112
+
63
113
  private
64
114
 
65
115
  # Informs an object that it was added to the list. In practice it adds
@@ -72,19 +122,19 @@ module Xcodeproj
72
122
  objects = [objects] unless objects.is_a?(Array)
73
123
  objects.each do |obj|
74
124
  obj.add_referrer(owner)
75
- attribute.validate_value(obj)
125
+ attribute.validate_value(obj) unless obj.is_a?(ObjectDictionary)
76
126
  end
77
127
  end
78
128
 
79
129
  # Informs an object that it was removed from to the list, so it can
80
- # remove it from its referrers and take the appropriate actions.
130
+ # remove its owner from its referrers and take the appropriate actions.
81
131
  #
82
132
  # @return [void]
83
133
  #
84
134
  def perform_deletion_operations(objects)
85
135
  objects = [objects] unless objects.is_a?(Array)
86
136
  objects.each do |obj|
87
- obj.remove_referrer(owner)
137
+ obj.remove_referrer(owner) unless obj.is_a?(ObjectDictionary)
88
138
  end
89
139
  end
90
140
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcodeproj
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0.rc2
4
+ version: 0.4.0.rc3
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-22 00:00:00.000000000 Z
12
+ date: 2012-10-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -60,6 +60,7 @@ files:
60
60
  - lib/xcodeproj/config.rb
61
61
  - lib/xcodeproj/constants.rb
62
62
  - lib/xcodeproj/helper.rb
63
+ - lib/xcodeproj/project/object/aggregate_target.rb
63
64
  - lib/xcodeproj/project/object/build_configuration.rb
64
65
  - lib/xcodeproj/project/object/build_file.rb
65
66
  - lib/xcodeproj/project/object/build_phase.rb
@@ -69,10 +70,12 @@ files:
69
70
  - lib/xcodeproj/project/object/file_reference.rb
70
71
  - lib/xcodeproj/project/object/group.rb
71
72
  - lib/xcodeproj/project/object/native_target.rb
73
+ - lib/xcodeproj/project/object/reference_proxy.rb
72
74
  - lib/xcodeproj/project/object/root_object.rb
73
75
  - lib/xcodeproj/project/object/target_dependency.rb
74
76
  - lib/xcodeproj/project/object.rb
75
77
  - lib/xcodeproj/project/object_attributes.rb
78
+ - lib/xcodeproj/project/object_dictionary.rb
76
79
  - lib/xcodeproj/project/object_list.rb
77
80
  - lib/xcodeproj/project/recursive_diff.rb
78
81
  - lib/xcodeproj/project.rb
@@ -99,7 +102,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
102
  version: '0'
100
103
  segments:
101
104
  - 0
102
- hash: 2919884453979069373
105
+ hash: 1005029667767319661
103
106
  required_rubygems_version: !ruby/object:Gem::Requirement
104
107
  none: false
105
108
  requirements: